htmlangularjswebix

AngularJS / Webix Form - Can't enable button after setting ng-disabled value?


The following template, shown below controller snippet, is persistently disabling the submit button in AngularJS. I have tried to use $scope.$apply(); on the last line of $scope.getTextValueAndValidate function but when that line executes my form loses all entries (clears entirely).

How do I resolve this to make my button enabled and prevent clearing the form fields after all entries are valid?

Controller Snippet ($scope.valid checks if form fields not shown are filled out)

angular.module('Risk').controller('CreateRiskController', ['$http', '$resource', '$scope', '$state', '$window', '$timeout', '$interval', '$sce', 'CommonService', function($http, $resource, $scope, $state, $window, $timeout, $interval, $sce, CommonService){

  $scope.flags = {
    disabled: true
  }


  $scope.valid = function(){
            return($scope.risk.risktitle.trim() != '' &&
                   $scope.risk.riskstatement.trim() != '' &&
                   $scope.risk.context.trim() != '' &&
                   $scope.risk.closurecriteria.trim() != '' &&
                   $scope.risk.likelihood.trim() != '' &&
                   $scope.risk.technical.trim() != '' &&
                   $scope.risk.technical.trim() != '' &&
                   $scope.risk.cost.trim() != '' &&
                   !isNaN($scope.risk.likelihood) && Number($scope.risk.likelihood) >= 1 && Number($scope.risk.likelihood) <= 5 &&
                   !isNaN($scope.risk.technical) && Number($scope.risk.technical) >= 1 && Number($scope.risk.technical) <= 5 && 
                   !isNaN($scope.risk.schedule) && Number($scope.risk.schedule) >= 1 && Number($scope.risk.schedule) <= 5 &&
                   !isNaN($scope.risk.cost) && Number($scope.risk.cost) >= 1 && Number($scope.risk.cost) <= 5);
        }



  $scope.getTextValueAndValidate = function(obj, model, field){
        $scope.clearValidation(field);  
        CommonService.getTextValue(obj, model, 'risk', field); 
        $scope.validate(obj, field);
        valid = $scope.valid();
        $scope.flags.disabled = !valid;
  }
}]);

Template

<div id="formcontainer" ng-app="Risk" ng-controller="CreateRiskController" ng-init="init()">
    <div id="mycreateform" class="container" type="space" layout-padding="" ng-cloak="">   
        <init-risk />
        <form webix-ui="config" id="form" name="CreateRisk" role="form" ng-submit="valid() && submit()" novalidate>


 <table id="details" class="layout" border="1">
                <tr>
                    <td class="label">
                        Title
                    </td>
                    <td class="locked">
                        <div webix-ui="risktitleConfig" id="risktitle" name="risktitle" />
                    </td>
                </tr>
                <tr>    
                    <td class="label">
                        Risk Statement
                    </td>
                    <td class="locked">
                        <div webix-ui="riskstatementConfig" id="riskstatement" name="riskstatement" />
                    </td>
                </tr>
                <tr>
                    <td class="label">
                        Context
                    </td>
                    <td class="locked">
                        <div webix-ui="contextConfig" id="context" name="context" />
                    </td>
                </tr>
                <tr>
                    <td class="label">
                        Closure Criteria
                    </td>
                    <td class="locked">
                        <div webix-ui="closurecriteriaConfig" id="closurecriteria" name="closurecriteria" />
                    </td>
                </tr>
                 <!--tr class="text">
                        <td class="label">
                            Category
                        </td>
                        <td class="locked">
                             <div id="category" name="category" />
                        </td>
                  </tr-->
            </table>
            <h2>Initial Risk Assessment</h2>
            <div class="nested">
                <div class="info">
                    <table id="details" border="1">
                        <tr>
                            <td class="label">
                                Likelihood
                            </td>
                            <td class="locked">
                                <div webix-ui="likelihoodConfig" id="likelihood" name="likelihood" />
                            </td>
                        </tr>
                        <tr>
                            <td class="label" colspan="2">
                                Consequence
                            </td>
                        </tr>
                         <tr>
                            <td class="label margin-left">
                                Technical
                            </td>
                            <td class="locked">
                                <div webix-ui="technicalConfig" id="technical" name="technical" />
                            </td>
                        </tr>
                         <tr>
                            <td class="label margin-left">
                                Schedule
                            </td>
                            <td class="locked">
                                <div webix-ui="scheduleConfig" id="schedule" name="schedule" />
                            </td>
                        </tr>
                         <tr>
                            <td class="label margin-left">
                                Cost
                            </td>
                            <td class="locked">
                                <div webix-ui="costConfig" id="cost" name="cost" />
                            </td>
                        </tr>
                    </table>

            <button type="submit" ng-disabled="flags.disabled" class="raised primary">Create Risk</button>
        </form>
     </div>
</div>

Directive (inner relevant portion shown)

                function getLevelConfig(attr)
                {
                    var config = 
                    {
                        view:"text",
                        value: scope.risk[attr],      
                        on: {
                            "onChange": function(){var obj = this.eventSource || this; scope.getTextValueAndValidate(obj, scope, attr); assignRiskLevel();}
                        },
                        attributes: {
                            maxlength: 1
                        },
                        responsive: true,
                        width: "36",
                        height: "30",
                        required: true
                    };
                    return config;
                }

                function getTextConfig(attr)
                {
                    var config = 
                    {
                        view:"text",
                        value: scope.risk[attr],      
                        on: {
                            "onChange": function(){ var obj = this.eventSource || this; scope.getTextValueAndValidate(obj, scope, attr)}
                        },

                        responsive: true,
                        width: "520",
                        height: "30",
                        validate: webix.rules.isNotEmpty,
                        required: true
                    };
                    return config;
                }

                function getTextareaConfig(attr)
                {
                    var config = 
                    {
                        view:"textarea",
                        value: scope.risk[attr],
                        on: {                                  
                            "onChange": function(){var obj = this.eventSource || this; scope.getTextValueAndValidate(obj, scope, attr)},
                            //"onBlur": function(){scope.validate(scope.actionitem.actionitemstatement, 'actionitemstatement')}
                        },
                        responsive: true,
                        width: "520",
                        height: "97",
                        validate: webix.rules.isSelected,
                        required: true
                    };

                    return config;
                }

                function getSelectConfig(attr, options)
                {
                    var config = 
                    {
                        view: "richselect",
                        value: scope.risk[attr], 
                        options: options,
                        on: {
                            //"onChange": function(){var obj = this.eventSource || this; getValue(obj, 'assignor')},
                            "onChange": function(){var obj = this.eventSource || this; scope.getItemValueAndValidate(obj, scope, attr)}
                            //"onBlur": function(){scope.validate(scope.actionitem.assingor, 'assignor')}
                        },
                        responsive: true,
                        width: "520",
                        height: "30",
                        validate: webix.rules.isSelected,
                        required: true
                    };
                    return config;
                }


                scope.risktitleConfig = getTextConfig('risktitle');

                scope.riskstatementConfig = getTextareaConfig('riskstatement');

                scope.contextConfig = getTextareaConfig('context');

                scope.closurecriteriaConfig = getTextareaConfig('closurecriteria');

                scope.categoryConfig = getSelectConfig('category');

                scope.likelihoodConfig = getLevelConfig('likelihood');

                scope.technicalConfig = getLevelConfig('technical');

                scope.scheduleConfig = getLevelConfig('schedule');

                scope.costConfig = getLevelConfig('cost');

Solution

  • I found a helpful solution to my problem that worked, despite not directly using an angular directive.

    How to set ng-disabled inside directive

    Modifying my solution was straightforward with the suggestion.

    I manipulated the DOM in side my own directive instead of using AngularJS's ng-disabled directive.

    if (scope.valid())
         (document.querySelector('#submit')).removeAttribute('disabled');
    else
         (document.querySelector('#submit')).setAttribute('disabled', 'disabled');
    

    I then added an id to my button an a disabled attribute initialized to disabled in my template.

     <button id="submit" type="submit" disabled="disabled" class="raised primary">Create Risk</button>