如何在Aurelia验证渲染器中将VM组合到视图中 [英] How can I compose a VM into a view within an Aurelia validation renderer

查看:42
本文介绍了如何在Aurelia验证渲染器中将VM组合到视图中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to use the aurelia-validation plugin to perform validation on a form. I'm creating a custom validation renderer that will change the color of the input box as well as place an icon next to the box. When the icon is clicked or hovered, a popup message appears that will display the actual error message.

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

Currently, I'm rendering all of this in code manually in the renderer, but it seems like it would be nice to have the html for all of this defined in an html file along with the associated js file to handle the click and hover on the icon. IOW, encapsulate all the error stuff (icon with popup) in a View/ViewModel and then in the render() of my validation renderer, somehow just compose a new instance of this just after the element in question.

这有可能吗?我已经看过如何使用<compose></compose>元素,但是我实际上是在试图避免将其添加到所有表单的输入框中.

Is this possible to do? I've seen how to use <compose></compose> element but I really am trying to avoid having to add that to all of my forms' input boxes.

这是我目前在渲染器中拥有的:

This is what I currently have in my renderer:

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
    }
}

感谢您可以提供的任何帮助.

Thanks for any help you can offer.

P.S.在这一点上,我还没有实现我所提到的点击或悬停,这是我想做的事情,但是我什至不知道在这一点上如何做.如果我可以组成虚拟机,那就更简单了.

P.S. At this point, I am not implementing a click or hover like I mentioned -- that is something that I would like to do but I'm not even sure how at this point. Would be more straight forward if I can compose a VM.

编辑

有人指出我 Aurelia Gitter频道上某人的这篇文章.我已经尝试实现TemplatingEngine,但是显然我并没有以正确的方式进行操作.这就是我所拥有的.

I was pointed to this article by someone on the Aurelia Gitter channel. I've tried implementing the TemplatingEngine but clearly I'm not going about it the right way. Here's what I have.

add-person-dialog.js //具有验证形式的虚拟机

add-person-dialog.js //VM that has form with validation

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))
     }

icon-validation-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})
    }
 }

field-error-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>.

Ultimately, <field-error-info></field-error-info> gets added to the DOM but doesn't actually get rendered. (Incidentally, I also tried adding <require from='./elements/field-error-info'></require> in the add-person-dialog.html.

推荐答案

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

You could create a form control custom element that encapsulates the error icon and tooltip logic. The element could expose two content projection slots to enable passing in a label and input/select/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

这篇关于如何在Aurelia验证渲染器中将VM组合到视图中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆