Binding input number with text in AngularJS - javascript

I need to bind inputs of type 'number' with a different models which are strings. I've managed to bind them using a directive like:
app.directive('input', function () {
return {
restrict: 'E',
require: 'ngModel',
priority:999999,
link: function (scope, elem, attrs, ctrl) {
//Check del tipo input
if (attrs.type.toLowerCase() !== 'number')
{
return;
}
//Paso a numero el valor a colocar
ctrl.$formatters.push(function (value)
{
return value ? parseFloat(value) : null;
});
}
};
});
And the HTML is like this:
<input class="form-control" type="number" ng-model="scopeValue" />
Up to here, there is no problem with binding. But, when I write a ng-repeat and ng-switch combined this directive is not executed. Sample code:
<div ng-repeat="attribute in attributes" ng-switch on="attribute.type">
<div class="input-group">
<span class="input-group-addon" id="basic-addon2">{{attribute.label}}</span>
<input class="form-control" ng-switch-when="text" ng-model="attribute.value" type="text" name="{{attribute.label}}" value="{{attribute.value}}">
<input class="form-control" ng-switch-when="number" ng-model="attribute.value" type="number" name="{{attribute.label}}" value="{{attribute.value}}">
</div>
</div>
Here the directive link code is never thrown and the inputs with number are never completed. As far as I know, the directive checks all the inputs and has the ngModel dependence. Why is it never executed?

Related

AngularJS Form custom validation. Cannot read property '$validators' of undefined

I want to create a custom form validation, using AngularJS. That form should have input and select elements. The form should be valid, when either imputs are empty or both filled with some values. Here is the view:
<form name="recipientsForm" novalidate>
<md-input-container>
<label>Name</label>
<input name="name" type="text" ng-model="relationship.name" value="" empty-or-both-filled="relationship.relationshipType">
<div ng-messages="recipientsForm.name.$error">
<div ng-message="emptyOrBothFilled">Enter name.</div>
</div>
</md-input-container>
<md-input-container>
<md-select name="type" placeholder="Select your relation... " ng-model="relationship.relationshipType" empty-or-both-filled="relationship.name">
<md-option ng-repeat="type in relationshipTypes" value="{{type.relationshipType}}">
{{type.name}}
</md-option>
</md-select>
<div ng-messages="recipientsForm.type.$error">
<div ng-message="emptyOrBothFilled">Pick relationship.</div>
</div>
</md-input-container>
</form>
And here is the directive:
(function () {
'use strict';
angular
.module('app')
.directive('emptyOrBothFilled', [emptyOrBothFilled]);
function emptyOrBothFilled() {
return {
restrict: 'A',
required: 'ngModel',
scope: {
targetNgModel: '=emptyOrBothFilled'
},
link: function($scope, element, attrs, ngModel) {
ngModel.$validators.emptyOrBothFilled = function(val) {
var isValueEmpty = !val;
var isTargetEmpty = !$scope.targetNgModel;
return (isTargetEmpty && isValueEmpty) || (!isTargetEmpty && !isValueEmpty);
}
$scope.$watch('targetNgModel', function() {
ngModel.$validate();
})
}
}
}
})();
Prompt, please, why do I get this error:
TypeError: Cannot read property '$validators' of undefined
at link (http://localhost:3000/app/shared/directives/EmptyOrBothFilled.js:17:24)
It should be
require: 'ngModel',
not
required: 'ngModel',
in the directive specification.

How to select dynamically generated elements from inside an AngularJS directive?

In my directive, I need to select out certain DOM elements, some of which are generated dynamically in an ng-repeat loop. If I do it in a straightforward way, I will only get the static elements. However, if I delay the selection by, say, 500ms, I will get all elements, which is what I want.
Although this works, it is not an ideal solution, and certainly doesn't seem like best practise. On the one hand, you'd like to keep the timeout as short as possible, but on the other hand, you want to be sure that the DOM is ready before selecting.
Is there an event which fires when all dynamic DOM is ready? What is the recommended way to select dynamically generated elements from an AngularJS directive?
EXAMPLE:
HTML:
<div data-my-directive>
<div class="modal-body">
<label data-localize>type:</label>
<select class="form-control" ng-model="assetFilter.appCode" ng-change="loadassets(assetFilter.appCode)" ng-options="type.code as type.name for type in types"></select>
<table class="table table-default" ng-show="hasLoaded">
<tbody ng-repeat="asset in assets | filter:assetFilter | orderBy:'assetKey':false">
<tr>
<td>
<div class="container-fluid">
<div class="row vert-align">
<div class="col-sm-4">
{{asset.assetKey}}
</div>
<div class="col-sm-8" style="height:100%">
<input ng-hide="asset.assetKey.length >= 80" type="text" class="form-control" ng-model="asset.assetValue" ng-change="asset.isModified=true">
<textarea ng-show="asset.assetKey.length > 80" class="form-control" ng-model="asset.assetValue" ng-change="asset.isModified=true"></textarea>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="save(saveassets, $event)" ng-disabled="!(assets | anyModified)" data-localize>Save</button>
<button class="btn btn-warning" ng-click="close($event)" data-localize>Close</button>
</div>
</div>
Directive:
myApp.directive('myDirective', function ($timeout) {
return {
restrict: 'A', //attribute only
link: function (scope, elem, attr, ctrl) {
var context = elem[0];
var availableFormElements = 'input:not([disabled]):not([class*=ng-hide]),' +
'select:not([disabled]):not([class*=ng-hide]), textarea:not([disabled]):not([class*=ng-hide]),' +
'button:not([disabled]):not([class*=ng-hide]),' +
'*[class*=btn]:not([disabled]):not([class*=ng-hide])';
var allFormElements = context.querySelectorAll(availableFormElements);
// Will only get static elements, nothing from ng-repeat loop
$timeout(function () {
allFormElements = context.querySelectorAll(availableFormElements);
// Will include all elements, also from ng-repeat loop
}, 500);
// Code to manipulate selected form elements
};
});
This is a simple example how you could work it out.
Imo the only drawback to this solution is you can't use an isolate scope.
html
<div data-ng-controller="MainController">
<div outer-directive>
<ul>
<li ng-repeat="asset in assets" inner-directive>
{{asset}}
<input type="text" class="form-control">
</li>
</ul>
</div>
</div>
js
var app = angular.module('myApp', []);
app.controller('MainController',function($scope) {
$scope.assets = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
});
app.directive('outerDirective', function() {
return {
restrict: 'A',
controller: function($scope) {
}
};
});
app.directive('innerDirective', function() {
return {
restrict: 'A',
require: '^outerDirective',
link: function(scope, elem, attrs,ctrl) {
var context = elem[0];
if (scope.$last){
var availableFormElements = 'input,textarea';
var allFormElements = context.querySelectorAll(availableFormElements);
console.log(allFormElements);
}
}
};
});
or better
.directive('myParent', function ($timeout) {
return {
restrict: 'A', //attribute only
controller: function ($scope, $element) {
this.isDone = function(){
var context = $element[0];
var availableFormElements = 'input,textarea';
var allFormElements = context.querySelectorAll(availableFormElements);
console.log(allFormElements);
}
}
};
})
.directive('myChild', function ($timeout) {
return {
require:'^myParent',
restrict: 'A', //attribute only
link: function (scope, elem, attr, ctrl) {
if (scope.$last){
ctrl.isDone();
}
}
};
})
BTW
Don't touch the dom in the controller :)

How data is passed from custom directive view to controller?

code for the directive template
//"textBox.html"
<div class="well">
<label class="control-label">Text</label>
<div class="controls">
<input id="label" type="text" class="txt span3" ng-model="label" placeholder='Label for text field...'>
<input type="text" class="span3" ng-model="value" placeholder='Default value...'>
<input type="text" class="span3" ng-model="helpText" placeholder="Help text...">
<input type="checkbox" class="span1" ng-model="required" ng-true-value="true" ng-false-value="false">Required
<input type="checkbox" class="span1" ng-model="advanced" ng-true-value="true" ng-false-value="false">Advanced?
<img src="../../images/bullet_cross.png" alt="Remove" style="cursor: pointer" id="text" border="0" ng-click="deleteField($event)">
</div>
</div>
directive is using like this in main html page
//"algorithm.html"
<text-box></text-box>
controller for the custom directive
//"controller.js"
var algorithm = angular.module('algorithmController',[]);
/***********directive to render text field***********/
algorithm.directive('textField' , function(){
return{
restrict: 'E',
templateUrl: '../partials/algorithm/textBox.html',
require: 'ngModel',
replace: true,
link: function(scope, iElement, iAttrs, ngModelCtrl) {
// how should i get updated data(i.e. if user change after typing) over here entered by user??
}
};
});
You can create an isolate scope using the '=' syntax, which will create two way binding to your controller and the directive. You don't even necessarily need ngModel required in your directive.
.directive("textField", function () {
return {
restrict : "E",
template : "<input type='text' ng-model='val'/>",
scope : {
val : "="
}
};
});
Here is a very simple example doing what you requested;
http://jsfiddle.net/smaye81/xaohrv53/2/

$setValidity inside validRegex directive

I have directive like this:
.directive('validRegex', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.unshift(function(viewValue) {
console.log(viewValue);
try {
var regex = new RegExp(viewValue);
ngModel.$setValidity('notRegex', true);
return viewValue;
} catch(e) {
ngModel.$setValidity('notRegex', false);
return undefined;
}
});
}
};
})
and I use it like:
<div class="col-sm-7">
<input class="form-control" valid-regex id="search-text" type="text" ng-model="selectedSearchText"/>
<span ng-show="selectedSearchText.$error.notRegex" class="form-error">
Invalid Regular Expression
<span class="icon-attention app_icon"></span>
</span>
</div>
<p>{{selectedSearchText}}</p>
If regex is invalid the the text don't show up as expected but no error message. I've search SO but didn't find a fix.
You have to enclose the input field with in a form as follows
<form name="form">
<div class="col-sm-7">
<input class="form-control" valid-regex id="search-text" type="text" ng-model="selectedSearchText" name="selectedSearchText"/>
<span ng-show="form.selectedSearchText.$error" class="form-error">
Invalid Regular Expression
<span class="icon-attention app_icon"></span>
</span>
</div>
<p>{{selectedSearchText}}</p>
</form>

using datepicker on selecting date value not binding to model Angular js

i am using datepicker but here facing problem regarding model value not binding to model when i select date its nothing happen, any one can tell me where i am doing wrong must be appreciated. here i am sending my code.Showing date picker just problem after selecting date value not not binding to ng-model="user.dob".
signUpview.html
<div class="col-md-6">
<label for="datepicker" class="col-lg-5 form-label">Date Of Birth:</label>
<div class="col-lg-7">
<input type="text" class="form-control dateBirth" ng-model="user.dob" id="datepicker" name="datepicker" datepicker placeholder="Date Of Birth" required/>
<div class="error" ng-show="newUser_form.datepicker.$dirty && newUser_form.datepicker.$invalid">
<small class="error errorFields" ng-show="newUser_form.datepicker.$error.required"> Date is required.</small>
</div>
</div>
</div>
datepickerDirective.js
app.directive('datepicker', function() {
var linker = function(scope, element, attrs) {
element.datepicker().on('changeDate', function(){
console.log(scope);
$(".datepicker").hide();
});
}
return {
require: 'ngModel',
restrict: 'A',
link: linker
}
});
you can use ngModel.$setViewValue update the model property
app.directive('datepicker', function() {
var linker = function(scope, element, attrs,ngModelCtrl) {
element.datepicker().on('changeDate', function(){
console.log(scope);
ngModelCtrl.$setViewValue(value);//value is datepicker selected date;
$(".datepicker").hide();
});
}
return {
require: 'ngModel',
restrict: 'A',
link: linker
}
});

Categories