Disable submit button based on fields added with ng-bind-html

JSFiddle here: http://jsfiddle.net/c6tzj6Lf/4/

I dynamically create forms and buttons and want to disable the buttons if the required form inputs are not completed.

HTML:

<div ng-app="choicesApp"> <ng-form name="choicesForm" ng-controller="ChoicesCtrl"> <div ng-bind-html="trustCustom()"></div> <button ng-repeat="button in buttons" ng-disabled="choicesForm.$invalid"> {{button.text}} </button> </ng-form> </div> 

JavaScript:

 angular.module('choicesApp', ['ngSanitize']) .controller('ChoicesCtrl', ['$scope', '$sce', function($scope, $sce) { $scope.custom = "Required Input: <input required type='text'>"; $scope.trustCustom = function() { return $sce.trustAsHtml($scope.custom); }; $scope.buttons = [ {text:'Submit 1'}, {text:'Submit 2'}]; }]); 

choicesForm.$invalid false and does not change when entering text in the input field.

Decision:

I ended up using the angular -bind-html-compile directive: https://github.com/incuna/angular-bind-html-compile

Here is the corresponding bit of working code:

 <ng-form name="choicesForm"> <div ng-if="choices" bind-html-compile="choices"></div> <button ng-click="submitForm()" ng-disabled="choicesForm.$invalid"> Submit </button> </ng-form> 

And the selection can be an HTML snippet as follows:

 <div><strong>What is your sex?</strong></div> <div> <input type="radio" name="gender" ng-model="gender" value="female" required> <label for="female"> Female</label><br> <input type="radio" name="gender" ng-model="gender" value="male" required> <label for="male"> Male</label> </div> 
+8
javascript html angularjs
source share
5 answers

The main problem is that ngBindHtml does not compile html - it embeds html like this. You can even check dynamic input and see that it does not have ngModel CSS classes ( ng-pristine , ng-untouched , etc.). which is the main red flag.

In your case, the form simply does not know that you have added another input or something has changed. Its state ($ pristine, $ valid, etc.) is not determined by its HTML, but by the registered NgModelControllers . These controllers are automatically added when ngModel is bound.

  • For example, this <input required type='text'> will not affect the correctness of the form, even if it is necessary, since it does not have an ngModel assigned to it.
  • But this <div ng-model="myDiv" required></div> will affect it, as it is required, and it is assigned ngModel.

The ngDisabled directive on your buttons works as expected, since it depends on enter $ invalid property .

See the fiddle for a demonstration of how ngModel registers its controller. Note that the html containing dynamic input compiles after 750 ms only to show how NgModelControllers can be added after FormController . p>

In your case, there are several solutions:

  • use custom directive to bind and compile html - for example this

  • use ngInclude which compiles html

  • use $ compile to compile the newly added HTML, but it's a little complicated, because you don’t know exactly when to complete this action

+6
source share

This is an answer, but not a complete one, because I cannot execute the code at the moment.

I think your html will be included, not compiled. Thus, the inputs are not bound to angular and are not part of the angular form object.

The only way I can see is to use a directive that will compile the html submitted and add it to your form. This can be quite complicated, although if you want to go this route, I suggest editing your question to ask for the specified directive.

However, I am not very familiar with compiling $, so I don’t know if this will work, just add $ compile around $ sce.trustAsHtml ()

+2
source share

You can write a method, since ng-disabled does not work with booleans, it works instead of the string 'checked':

So, on your controller, place the method:

 $scope.buttonDisabled = function(invalid){ return invalid ? "checked" : ""; }; 

And in your opinion, use it in an angular expression:

 <button ng-repeat="button in buttons" ng-disabled="buttonDisabled(choicesForm.$invalid)"> 

Here is a working fiddle

+1
source share

Working demo

This is the solution you are looking for. You need a special directive. In my example, I used a directive called compile-template and included it in the div element.

 <div ng-bind-html="trustCustom()" compile-template></div> 

Directive Code:

 .directive('compileTemplate', function($compile, $parse){ return { link: function(scope, element, attr){ var parsed = $parse(attr.ngBindHtml); function getStringValue() { return (parsed(scope) || '').toString(); } //Recompile if the template changes scope.$watch(getStringValue, function() { $compile(element, null, -9999)(scope); //The -9999 makes it skip directives so that we do not recompile ourselves }); } } }); 

I found a directive in this script .

+1
source share

I believe what is actually happening, although due to jsfiddle I cannot reveal the real areas created here.

 <div ng-app="choicesApp"> <ng-form name="choicesForm" ng-controller="ChoicesCtrl"> <div ng-bind-html="trustCustom()"></div> <button ng-repeat="button in buttons" ng-disabled="choicesForm.$invalid"> {{button.text}} </button> </ng-form> </div> 

The first div is the top-level area, your form is the first child area. Adding a div using the function creates a dynamically added input field as a child of the first child, the grandson of the top-level area. Therefore, your form does not know which elements you are adding dynamically, as a result of which only a static field is required for a valid form entry.

A better solution would be to use ng-incue for extra form fields, or if your form is not large, just put them on the page or template that you are using.

+1
source share

All Articles