如何将VM组合到Aurelia验证渲染器中的视图中

时间:2017-01-19 15:08:43

标签: aurelia aurelia-validation

我正在尝试使用aurelia-validation插件对表单执行验证。我正在创建一个自定义验证渲染器,它将更改输入框的颜色以及在框旁边放置一个图标。单击或悬停图标时,会出现一条弹出消息,显示实际的错误消息。

enter image description here

目前,我在渲染器中手动渲染所有这些代码,但似乎在html文件中定义所有这些html以及关联的js文件来处理点击会很好并将鼠标悬停在图标上。 IOW,在View / ViewModel中封装所有错误内容(带有弹出窗口的图标),然后在我的验证渲染器的render()中,以某种方式只是在有问题的元素之后组成一个新的实例。

这可能吗?我已经看过如何使用<compose></compose>元素,但我真的想避免将其添加到我的所有表单的输入框中。

这是我目前在渲染器中的内容:

import {ValidationError, RenderInstruction} from 'aurelia-validation'

export class IconValidationRenderer {
    render(instruction){
        //Unrender old errors
        for(let {result, elements} of instruction.unrender){
            for(let element of elements){
                this.remove(element, result);
            }
        }

        //Render new errors
        for(let {result, elements} of instruction.render){
            for(let element of elements){
                this.add(element, result)
            }
        }
    }

    add(element, result){
        if(result.valid) 
            return

        //See if error element already exists
        if(element.className.indexOf("has-error") < 0){
            let errorIcon = document.createElement("i")
            errorIcon.className = "fa fa-exclamation-circle"
            errorIcon.style.color = "darkred"
            errorIcon.style.paddingLeft = "5px"
            errorIcon.id = `error-icon-${result.id}`
            errorIcon.click = ""
            element.parentNode.appendChild(errorIcon)

            element.classList.add("has-error")
            element.parentNode.style.alignItems = "center"

            let errorpop = document.createElement("div")
            let errorarrow = document.createElement("div")
            let errorbody = document.createElement("div")
            errorpop.id = `error-pop-${result.id}`
            errorpop.className = "flex-row errorpop"
            errorarrow.className = "poparrow"
            errorbody.className = "flex-col popmessages"
            errorbody.innerText = result.message
            console.log("Computing position")

            let elemRec = errorIcon.getBoundingClientRect()
            let elemH = errorIcon.clientHeight
            errorpop.style.top = elemRec.top - 10 + "px"
            errorpop.style.left = elemRec.right + "px"

            errorpop.appendChild(errorarrow)
            errorpop.appendChild(errorbody)
            element.parentNode.appendChild(errorpop)
        }
    }

    remove(element, result){
        if(result.valid)
            return

        element.classList.remove("has-error")
        let errorIcon = element.parentNode
            .querySelector(`#error-icon-${result.id}`)
        if(errorIcon)
            element.parentNode.removeChild(errorIcon)

        //Need to remove validation popup element
    }
}

感谢您提供的任何帮助。

P.S。在这一点上,我没有像我提到的那样实现点击或悬停 - 这是我想做的事情,但我现在还不确定如何。如果我能组成一个虚拟机,会更直接。

修改

我被Aurelia Gitter频道的某人指出this文章。我已经尝试过实现TemplatingEngine,但很明显我没有采用正确的方法。这就是我所拥有的。

add-person-dialog.js //具有验证格式的VM

import {TemplatingEngine,NewInstance} from 'aurelia-framework'
import {ValidationController} from 'aurelia-validation'
import {IconValidationRenderer} from './resources/validation/icon-validation-renderer'

export class AddPersonDialog {
     static inject = [NewInstance.of(ValidationController),TemplatingEngine]

     constructor(vc, te){
         this.vc = vc
         this.vc.addRenderer(new IconValidationRenderer(te))
     }

图标验证-renderer.js

//Plus all the other bits that I posted in the code above
constructor(te){
   this.te = te
}

add(element, result){
    if(result.valid) return

    if(element.className.indexOf("has-error") < 0 {
        //replaced there error icon code above with this (as well as a few different variations
        let test = document.createElement("field-error-info")
        element.parentNode.appendChild(test)
        this.te.enhance({element: test})
    }
 }

字段-误差在info.html

<template>
    <require from="./field-error-info.css" ></require>

    <i class="fa fa-exclamation-circle" click.delegate="displayMessage = !displayMessage" mouseenter.delegate="displayMessage = true" mouseleave.delegate="displayMessage = false"></i>
    <div show.bind="displayMessage" class="flex-row errorpop" style="left:300px">
        <div class="poparrow"></div>
        <div class="flexcol popmessages">Message 1</div>
    </div>
</template>

最终,<field-error-info></field-error-info>被添加到DOM但实际上并没有被渲染。 (顺便提一下,我也尝试在add-person-dialog.html中添加<require from='./elements/field-error-info'></require>

1 个答案:

答案 0 :(得分:3)

您可以创建一个表单控件自定义元素,用于封装错误图标和工具提示逻辑。该元素可以暴露两个内容投影槽,以便传入标签和输入/选择/ etc:

<template>
  <div validation-errors.bind="errors"
       class="form-group ${errors.length ? 'has-error' : ''}">

    <!-- label slot -->
    <slot name="label"></slot>

    <!-- input slot -->
    <slot name="input"></slot>

    <!-- icon/tooltip stuff -->
    <span class="control-label glyphicon glyphicon-exclamation-sign tooltips"
          show.bind="errors.length">
      <span>
        <span repeat.for="errorInfo of errors">${errorInfo.error.message}</span>
      </span>
    </span>
  </div>
</template>

以下是如何使用它:

<template>
  <require from="./form-control.html"></require>

  <form novalidate autofill="off">

    <form-control>
      <label slot="label" for="firstName" class="control-label">First Name:</label>
      <input slot="input" type="text" class="form-control" 
             value.bind="firstName & validateOnChange">
    </form-control>

    <form-control>
      <label slot="label" for="lastName" class="control-label">Last Name:</label>
      <input slot="input" type="text" class="form-control" 
             value.bind="lastName & validateOnChange">
    </form-control>

  </form>
</template>

实例:https://gist.run/?id=874b100da054559929d5761bdeeb651c

请原谅蹩脚的工具提示css