Issues with validators in a template

9 posts, 0 answers
  1. Derek
    Derek avatar
    5 posts
    Member since:
    May 2016

    Posted 27 Feb Link to this post

    I have the following in side an HTML page:

    <!-- Template for simple search row -->
    <script id="simple-search-row" type="text/x-kendo-template">
        <div class="simple-search-row">
            <input name="fieldName"
                data-role="dropdownlist"
                data-text-field="columnDisplayName"
                data-value-field="columnName"
                data-bind="
                    value: field,
                    source: columnsDataSource"></input>
            <span data-for="fieldName" class="k-invalid-msg"></span>
            <input name="filter"
                data-role="dropdownlist"
                data-text-field="displayName"
                data-value-field="name"
                data-bind="
                    value: type,
                    source: filterTypesDataSource,
                    events: { change : criteriaChanged, dataBound : simpleSearchDDLDataBound }"
                style="width: 15em;"></input>
            <span data-for="filter" class="k-invalid-msg"></span>
            <input id="value-1" name="value-1" type="text"
                data-bind="
                    value: values[0]"></input>
            <span data-for="value-1" class="k-invalid-msg"></span>
            <span id="value-and" style="display: none;">#: translate('between_and') #</span>
            <input id="value-2" name="value-2" type="text" style="display: none;"
                data-bind="
                    value: values[1]"></input>
            <span data-for="value-2" class="k-invalid-msg"></span>
            <a href="\\\\#" data-bind="events: { click : removeSimpleSearchRow }">
                <span class="k-icon k-i-cancel"></span>
            </a>
            <a href="\\\\#" data-bind="events: { click : addSimpleSearchRow }">
                <span class="k-icon k-i-plus"></span>
            </a>
        </div>
    </script>
     
    <div id="simple-search-rows" class="ui relaxed grid" data-template="simple-search-row" data-bind="source: searchFilter.criteria"></div>

     

    "searchFilter.criteria" is a JS array object.  And then I have a custom validator:

    var simpleSearchValidator = $('#simple-search').kendoValidator({
            messages : {
                fieldname : '',
                filter : '',
                valueone : '',
                valuetwo : ''
            },
            rules: {
                fieldname : function (input) {
                    if (input.is('[name|=fieldName]')) {
                        if(input.val() === ''){
                            return false;
                        }
                    }
     
                    return true;
                },
                filter : function (input) {
                    if (input.is('[name|=filter]')) {
                        if(input.val() === ''){
                            return false;
                        }
                    }
     
                    return true;   
                },
                valueone : function (input) {
                    if (input.is('[name|=value-1]')) {
                        let filter = input.parent().find('[name|=filter]'),
                            criteria = (filter ? filter.val() : '');
                         
                        switch(criteria){
                            case 'EQUAL_TO':
                            case 'NOT_EQUAL_TO':
                                return true;
                        }
     
                        if(input.get(0).style.display === 'none') {
                            return true;
                        }
     
                        if(input.val() === ''){
                            return false;
                        }
                    }
     
                    return true;   
                },
                valuetwo : function (input) {
                    if (input.is('[name|=value-2]') && input.is('')) {
                        if(input.val() === ''){
                            return false;
                        }
                    }
     
                    return true;   
                }
            }       
        }).data('kendoValidator');

     

    The issue is that the validator's .validate() is called, it correctly identifies incorrect data based on the custom rule, however if say the fieldName input field is invalid, it displays the k-invalid-msg for EVERY row, not just the single row with the invalid data.  I am guessing this is because the name attributes for each row are not unique.   I tried creating a unique id in the template:

    <!-- Template for simple search row -->
    <script id="simple-search-row" type="text/x-kendo-template">
        <div class="simple-search-row">
            # var uid = windows.util.genUniqueId(); #
            <input name="fieldName#= uid #"
                data-role="dropdownlist"
                data-text-field="columnDisplayName"
                data-value-field="columnName"
                data-bind="
                    value: field,
                    source: columnsDataSource"></input>
            ....
        </div>
    </script>
     
    <div id="simple-search-rows" class="ui relaxed grid" data-template="simple-search-row" data-bind="source: searchFilter.criteria"></div>

     

    Unfortunately, that did not work as the uid was only created once, at the time the template was loaded, not for each row.

    Is there an easy way to generate a unique form name for the input elements in each row?

  2. Vasil
    Admin
    Vasil avatar
    1604 posts

    Posted 01 Mar Link to this post

    Hello Derek,

    Change:
    # var uid = windows.util.genUniqueId(); #
    <input name="fieldName#= uid #"
    To:
    <input name="fieldName#: data.yourField #"
    And you will get unique name for each inputs in your rows, where the "yourField" is for example the primary key of your table.

    Regards,
    Vasil
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Derek
    Derek avatar
    5 posts
    Member since:
    May 2016

    Posted 01 Mar in reply to Vasil Link to this post

    I actually already tried something similar.  However, the inline template seems to only be called once at the time the template is read/loaded, not once per row.  At your suggestions I tried:

    <input name="fieldName-#: data.yourField #"

     

    However, I end up with this in the final html:

    <input name="fieldName-undefined"

     

    I can somewhat verify this by doing the following:

        <div class="simple-search-row">
            <!-- #= JSON.stringify(data) # -->
    ...

     

    to which I get this in the source once:

    <!-- {}-->

  4. Vasil
    Admin
    Vasil avatar
    1604 posts

    Posted 02 Mar Link to this post

    Hello Derek,

    Check out this example, and inspect the input elemnets on each row. They are having unique names.
    http://dojo.telerik.com/aLUfO

    Regards,
    Vasil
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  5. Derek
    Derek avatar
    5 posts
    Member since:
    May 2016

    Posted 03 Mar Link to this post

    I checked you example, and it does work, however it only provides one-way data binding.  In my template I am binding to input fields via MVVM to get two way binding.
  6. Derek
    Derek avatar
    5 posts
    Member since:
    May 2016

    Posted 06 Mar Link to this post

    I have partially resolved this by adding a function to the view model to return a unique name and setting the form name via data binding.

    <input id="value-1" type="text"
        data-bind="
            value: values[0],
            attr: { name : value1Name }"></input>

     

    let criteria = {
        field: 'key',
        type: 'CONTAINS',
        values: [
            '',
            ''
        ],
        fieldName : function() {
            return 'fieldName-' + this.uid;
        },
        typeName : function() {
            return 'filter-' + this.uid;
        },
        value1Name : function() {
            return 'value-1-' + this.uid;
        },
        value2Name : function() {
            return 'value-2-' + this.uid;
        }
    };

    This works great for the input textboxes, but for the two dropdown lists it seems to mess up the value data binding. :-(

  7. Vasil
    Admin
    Vasil avatar
    1604 posts

    Posted 07 Mar Link to this post

    Hello Derek,

    I will be glad to debug and try to provide you further assistance on this issue. But could you please provide some runnable Dojo, that fully illustrate your requirements and current implementation.

    Regards,
    Vasil
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  8. Derek
    Derek avatar
    5 posts
    Member since:
    May 2016

    Posted 07 Mar Link to this post

    http://dojo.telerik.com/uLIDi

    If your remove the ",attr: { name : fieldName }" part in the MVVM, it correctly binds.

     

     

     

  9. Vasil
    Admin
    Vasil avatar
    1604 posts

    Posted 09 Mar Link to this post

    Hello Derek,

    Yes the attr binding is not supported for the DropDownList. To overcome this you may skip the assigning of name and id to the dropdown. And to make the validation work, you will need to find the element from the child collection of the parent row by index, rather than by name.

    Regards,
    Vasil
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Back to Top