I'm trying to create a input directive element with validation.
I'd like to manage error status in this directive.
There are 3 files
Index.html: uses this directive
textValid.js: contains directive code
textValid.html: contains the directive template
I create this directive
textValid.js
App.directive("textValid", function() {
return {
restrict: "E",
templateUrl: "tpl/textValid.html",
require: "?ngModel",
scope: {
name: "#",
element: "=",
model: "="
}
};
});
index.html
<form name="edit_form_ctrl.contract_edit_form" action="#" novalidate >
<div class="row">
<text-valid name="ncontract"model="edit_form_ctrl.contract.ncontract"
element="edit_form_ctrl.contract_edit_form.ncontract">
</text-valid>
</div>
</form>
and template textValid.html
<input type="text" name="name" ng-model="model" class="form-control" ng-required="true" value="{{model}}" />
<div>pristine: {{element.$pristine}}</div> <!--is always undefined-->
<div>Invalid: {{element.$error}}</div> <!--is always undefined-->
<span class="color-red" ng-if="element.$error.required &&!element.$pristine">
{{curLang.field_mandatory}}
</span>
I'm trying to get input control to check $error and $pristine value, but I cannot to achieve it.
I read all documentation and the book too, but with any results.
Does someone try to do that?
Thanks in advance
If you add {{double-curlies}} around the name attribute of the input element like so:
<input type="text" name="{{name}}" ng-model="model" class="form-control" ng-required="true" />
You should be able to access the ngModelController for it from inside text-valid with $scope.form[$scope.name]
A couple other notes:
using a value attribute on and element with ng-model attribute will not have an effect.
you have require: '?ngModel' in your directive definition, but there is no ng-model attribute on the text-valid element. This is ok, but you won't get any ngModelController being injected unless the text-valid element has an ng-model attribute.
Edit:
Because text-valid has isolate scope, to access the FormController, you would need to require it and bind it:
App.directive("textValid", function() {
return {
restrict: "E",
templateUrl: "tpl/textValid.html",
require: "^^form",
scope: {
name: "#",
element: "=",
model: "="
},
link: function($scope, elem, attr, FormCtrl){
$scope.form = FormCtrl;
// now you should be able to access $scope.form[$scope.name]
// (you *might* need to put any initialization that accesses it inside a $timeout to wait for it to be rendered/bound)
}
};
});
In template, you should then be able to access it like:
<div>pristine: {{form[name].$pristine}}</div>
<div>Invalid: {{form[name].$error}}</div>
Try this:
<input type="text" name="name" ng-model="model" class="form-control" ng-required="true" value="{{model}}" />
<div>pristine: {{form.name.$pristine}}</div> <!--is always undefined-->
<div>Invalid: {{form.name.$error}}</div> <!--is always undefined-->
<span class="color-red" ng-if="element.$error.required &&!element.$pristine">
{{curLang.field_mandatory}}
</span>
Related
I have a ng-repeat with input box in each repeated item. I have set the autofocus to input.
<input type="text" autofocus />
So autofocus will be applied to all items. However, there's a bug in iOS where the last input box is auto focused instead of the first one.
I need to set it to return true based on the condition as in:
<input autofocus="{{$first ? 'true' : 'false' }}" >
Any idea how to accomplish this with Angular?
Use a custom directive to focus an element
Directive
app.directive('autofocus', ['$timeout', function($timeout) {
return {
restrict: 'A',
link : function(scope, element,attrs) {
$timeout(function() {
if(attrs.autofocus==='true'){
element[0].focus();
}
});
}
}
}]);
Controller
app.controller('MainCtrl', function($scope) {
$scope.names = ['first','second','third','fourth','fifth'];
});
HTML
<div ng-repeat="name in names">
<input type="text" autofocus="{{$index==0}}" ng-model="name" />
</div>
Demo plunker link
I have the following template:
<dynamic-field name="Name" type="input" ng-model="temp.product.name"></dynamic-field>
<dynamic-field name="Price" type="input" ng-model="temp.product.price"></dynamic-field>
<dynamic-field name="Qty" type="input" ng-model="temp.product.qty"></dynamic-field>
Custom directive code:
app.directive('dynamicField', function() {
return {
restrict: 'E',
templateUrl: getTemplate('templates/single-field.html'),
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
// console.log($scope);
}
};
});
In directive template, the input field is displayed:
<div class="field">
<input type="text" ng-model="ngModel" /> <!-- if $temp.product.post_text in parent scope is set to "Test", it's displayed -->
</div>
The problem is, when I modify something inside the input (isolated scope) changes are not applied to the parent scope. I think the problem is that I use primitive here:
<input type="text" ng-model="ngModel" />
... but I'm not sure how to resolve this. Any suggestions?
You must be doing something wrong. If it's two-way bound, it's two-way bound.
function MainController() {
this.name = "test";
this.logCtrlName = function() {
alert(this.name);
}
}
function dynamicField() {
return {
restrict: 'E',
template: `
<div class="field">
<input type="text" ng-model="ngModel" />
</div>
`,
scope: {
ngModel: '='
}
};
}
angular.module('app', []);
angular.module('app')
.controller('MainController', MainController)
.directive('dynamicField', dynamicField);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MainController as ctrl">
<dynamic-field name="Name" type="input" ng-model="ctrl.name"></dynamic-field>
<a href ng-click="ctrl.logCtrlName();">Name inside parent controller</a>: {{ ctrl.name | json }}
</div>
</div>
Like you said since your model is primitive value, so whenever you change the value inside isolated scope will create its copy of scope variable.
A simple and quick way to fix that is create a function to update parent scope value $scope.$parent.ngModel directly then add ng-change to input element and call that function whenever input value is changed.
I have a directive that receives a data object and a function to it's isolate scope. In link function I'm declaring a scope method to trigger in a certain event (button click).
Problem is the value passed to the above mentioned method is available inside it, but the scope variable is still undefined.
Directive:
commentsModule.directive('commentsDirective', [ function() {
return {
restrict: 'E',
templateUrl: '/alarm-viewer-comments-template.html',
scope: {
alarmComments: "=value",
sendNewComment: "&sendNewComment"
},
link: function(scope, elems, attrs, ngModelCtrl) {
scope.sendComment = function(data) {
console.log(scope.newComment);//this newComment variable is undefined
scope.sendNewComment(data);//data is correct
scope.newComment = '';
};
}
}
}
]);
Here inside link function, data passed into scope.sendComment is available but yet scope.newComment gets undefined.
Template:
<h4>Comments</h4>
<div ng-repeat="comment in alarmComments.comments">
<p>{{comment.timestamp}} | <strong>{{comment.user}}</strong>: {{comment.commentType}} {{comment.comment}}</p>
</div>
<div ng-if="alarmComments.editPermission && alarmComments.isActiveAlarm">
<form name="commentsForm" role="form" track-form>
<input type="text" ng-model="newComment" pattern="/.{1,}" maxlength="4" required ng-enter="sendComment(newComment)"/>
<button type="button" class="btn btn-primary" ng-disabled="commentsForm.$invalid" ng-click="sendComment(newComment)">Send</button>
</form>
</div>
UI:
<comments-directive value="alarmComments" send-new-comment="addNewComment(comment)"></comments-directive>
Can someone help me out...?
edit: what I want is to clear the input text field after entering a comment.
Within directive scope you should map the newComment property also along with alarmComments. like below -
scope: {
alarmComments: "=value",
newComment: "=newComment",
sendNewComment: "&sendNewComment"
},
A good way to debug problems like this is render scope ids (scope.$id) and verify they are of the same id.
Could you verify during link, what is the scope.$id and render it in your template?
<h4>Comments</h4>
<div ng-repeat="comment in alarmComments.comments">
<p>{{comment.timestamp}} | <strong>{{comment.user}}</strong>: {{comment.commentType}} {{comment.comment}}</p>
</div>
<div ng-if="alarmComments.editPermission && alarmComments.isActiveAlarm">
<form name="commentsForm" role="form" track-form>
<input type="text" ng-model="newComment" pattern="/.{1,}" maxlength="4" required ng-enter="sendComment(newComment)"/>
<button type="button" class="btn btn-primary" ng-disabled="commentsForm.$invalid" ng-click="sendComment(newComment)">Send</button>
{{$id}}
</form>
</div>
Sometimes templates create its own scope and you might have to use $parent.newComment in your templates.
I have a directive HTML template like this:
textinput.html
<label for="{{name}}">{{label}}</label>
<input type="{{type}}" placeholder="{{placeholder}}" id="{{name}}" ng-model="{{name}}">
The label is outputting correctly, however everything inside of the input field is outputing as static {{varname}}
If I remove the ng-model like this:
<input type="{{type}}" placeholder="{{placeholder}}" id="{{name}}">
It outputs the variables correctly, but the moment I place the ng-model in and dynamically assign it a value, it breaks the entire input.
Why is this happening?
My goal is to be able to create simple 1 line text inputs which I can mass change with the directive, like so:
<textinput name="username" label="Username" type="text" placeholder="Enter Username"></textinput>
Finally figured it out, you have to pass the ng-model through using 2 way binding like this:
<textinput type="email" name="userEmail" ng-model="userEmail" placeholder="Email Address..." label="Email"></textinput>
-
app.directive('textinput', function() {
return {
restrict: 'E',
scope: {
label:'#label',
placeholder:'#placeholder',
name: '#name',
type: '#type',
ngModel: '=ngModel'
},
transclude: true,
templateUrl: 'directives/textinput.html'
};
});
Now within the template HTML file you can map properties without the {{ }} which works with ng-model.
example:
<label for="{{name}}">{{label}}</label>
<input type="{{type}}" placeholder="{{placeholder}}" id="{{name}}" ng-model="ngModel">
Now it'll be super easy to quickly generate re-usable form code.
So, I have a form, where I need to use a custom directive.
What i need: pass the user model to the directive.
<form>
<input type="text" ng-model="user.login">
<input type="password" ng-model="user.password">
<span ng-custom-directive ng-model="user.testfield"></span>
</form>
Directive template looks like this:
<span><input type="checkbox" ng-model="[HERE I NEED user.testfield TO WORK WITH user]"> </span>
How I can pass the user model to directive template?
After form submit I need user.testfield to be avaliable in the $scope.user like:
console.log($scope.user)
{
login: 'test',
password: 'test',
testfield: true|false
}
You can solve it in the other way plunker
In brief:
scope: {
bindedModel: "=ngModel"
},
template: '<input type="text" ng-model="bindedModel">'
Well, I found similar question and resolved my problem in this way:
angular.module("myApp")
.directive "ngCustomDirective", () ->
restrict: 'A',
scope:
field: '#',
model: '='
template: '<span><input type="checkbox" ng-model="model[field]"></span>'
And directive usage will be:
<span ng-custom-directive
ng-bind-model="user"
ng-bind-field="testfield">
</span>