Passing An Ng-Model Value to A Directive - angularjs

I've looked at the previous answers, but I'm not sure if they are the answer I need or not.
I have a directive, let's call it "selectValue". A value can have a default, let's call it "$scope.default".
The directive will look like this in one place:
<select-value ng-model="data.input" controlId="inputSelector" />
But it will look like this in another:
<select-value ng-model="myValue" controlId="inputSelector" />
I do not have the option of making the ng-model inputs the same; they are used in different places and this is a legacy code base.
Here is the definition of the directive:
.directive('selectValue', ['$timeout', function($timeout) {
const directive = {
restrict: 'E',
scope: {
controlId: '#',
model: '=?'
},
controller: 'selectValueCtrl',
template: '<input id="{{controlId}}" name="{{controlId}}" placeholder="Enter Value" type="text" ng-model="model" />'
};
return directive;
}
The question: what do I do to be able to enter different inputs in the "model" attribute of the <select-value> to have it access different scope variables?
Edit: the referenced "duplicate" question refers to setting a value for ng-click, not referencing ng-model in a form control.

From what I can tell, it looks as though you are trying to pass defaults with preset values. The problem you are facing is your select-value element is using the ng-model directive in an attempt to pass the data however your binding in your directive is 'model'.
In order to fix this issue, simply change the 'ng-model' to 'model' and your bindings should then work.
In the end, your element should look like so:
<select-value model="myValue" controlId="inputSelector" />
as opposed to:
<select-value ng-model="myValue" controlId="inputSelector" />

Related

directive's scope inside ng-repeat angularjs

I'm trying to understand directive's scope inside ng-repeat, still wondering if it comes from ng-repeat but it looks like.
Here is my code
directive.js
myApp.directive('dirSample', function () {
return {
template: '<input type="text" ng-model="name" />',
replace: true,
restrict: 'AE'
}
});
mainController.js
angular.controller('mainController',function($scope){
$scope.name = 'name'
});
index.htm
<div ng-repeat="i in [1, 2, 3, 4]">
<dir-sample></dir-sample>
</div>
<dir-sample></dir-sample>
<dir-sample></dir-sample>
When i make a change in one of the last two directives (which are not inside ng-repeat) it works well, changes on one are reflected on the other.
Problem :
1 - if i change an input value of a directive generated by ng-repeat , changes are not reflected anywhere else.
2 - if i change value of input on one of the two last directives , the directives inside ng-repeat change too, but if touch ( change input value ) of any directive , changes will not be reflected on that directive but will keep being reflected on the other directives.
Can someone please explain why the scope has that behavior ?
Thanks.
Binding primitives is tricky, as is explained here: Understanding scopes. It has to with how Javascript works. Your 'name' variable will get shadowed once it is altered within the ng-repeat block. The suggested fix (from the link above):
This issue with primitives can be easily avoided by following the
"best practice" of always have a '.' in your ng-models
They also provide a link to a video explaining exactly this problem: AngularJS MTV Meetup
So a fix looks like this:
app.controller('mainController',function($scope){
$scope.attr= {}
$scope.attr.name = 'name'
});
app.directive('dirSample', function () {
return {
template: '<input type="text" ng-model="attr.name" />',
replace: true,
restrict: 'AE'
}
});

pass ngKeyUp function into directive

I’ve got a directive/template that contains an input field.
The input field has an ngKeyup and an ngModel.
I want the ngKeyup function to be passed into the directive. The ngKeyup on the input field within the directive/template should invoke this function.
This plunker shows option 1 and option 2 http://plnkr.co/edit/kN8mitdG6pK5GNqGzYw5?p=preview
Option one is simplest and partially works, the function is simply passed in by '=', the directive references it in the ngKeyUp attribute
Directive
ngApp.directive("searchField", ['$parse',function ($parse) {
return {
restrict: "E",
scope: {
myKeyUp: '=',
Template
<input type="text" ng-model="model" ng-keyup="myKeyUp" />
This partially works, but the $event object is not passed.
In option two the directive receives the function from the controller as an '&', tries to $parse it and invoke it. This simply isn't working for me but I'm not very familiar with $parse.
ngKeyup can receive any parameters e.g. ng-keyup(a,b,c,$index,$event)
A key point/requirement is that this directive should be the same i.e. myKeyUp should be capable of accepting any parameters.
Any help or pointers much appreciated.
Thanks
John
It has to be '&' in scope, as it allows you to pass the function reference.
and what you have to do in the template is:
<input type="text" ng-model="model" ng-keyup="myKeyUp($event)" />
UPDATE:
Here is another approach that you could take: http://goo.gl/a27JrX
It turns out there's a really simple solution.
Quote from question
I want the ngKeyup function to be passed into the directive. The ngKeyup on the input field within the directive/template should invoke this function.
Turns out the div can simply have the ng-keyup attribute, it doesn't have to be on the input field.
This completely solves the problem.
http://plnkr.co/edit/xTigcDaSLpL9pvRtfY5J?p=preview
Now the directive takes only the model as a parameter. The ngKeyup is outside the directive.
ngApp.directive("searchField", ['$parse',function ($parse) {
return {
restrict: "E",
scope: {
model: '='
},
templateUrl: 'searchFieldTemplate',
replace: true,
controller: ['$scope','$attrs', function ($scope, $attrs) {
}]
};
}]);
And the template is now only concerned with the model
<div class="searchField">
<h4>Template</h4>
(observe the console)
<div>
<input type="text" ng-model="model" />
</div>
That actually makes allot of since when you think about it....

Declaring and using angular directives that map id, name, and ng-model to a single field

I'd like to create/use an AngularJS directive to avoid creating some redundant HTML and also to simplify how I use Bootstrap elements. I'd like to use a directive this way:
<myDirective id="person.lname" label="Last Name"></myDirective>
The template I'd like AngularJS to write is:
<label for="person.lname">Last Name</label>
<input id="person.lname" name="person.lname" ng-model="person.lname">
How would I declare a directive to be able to create this template and have the binding with ng-model still work? Are there any reasons why this would not be a good idea?
Thanks.
UPDATED
I added the label tag to reflect how the id/name would be used for the input element. The generated template would allow you to click on the label and have the focus be placed on the input element.
This should do what you want:
.directive('myDirective', function() {
return {
scope: {
model: '=identifier',
id: '#identifier',
label: '#',
},
restrict: 'E',
template: '<label for="{{id}}">{{label}}</label><input id="{{id}}" name="{{id}}" ng-model="model">'
};
})
View:
<my-directive label='Last name' identifier="person.lname"></my-directive>
Fiddle

Angular JS directives as native inputs

How can I do this thing:
HTML:
{{bar}}
<input type="text" ng-model="bar">
<foo ng-model="bar">
JS:
app.directive('foo', function(){
return {
restrict: 'E',
template: '<textarea>{{value}}</textarea>',
scope: { value : '=' }
controller: function($scope, $element){
}
}
});
I want change "bar" value when foo directive changes and change value in foo directive when text input changes.
How can I do that?
text input changes: textarea changes.
textarea changes: text input changes too.
but textarea should be as directive with restrict: "E"
So, your problem is that your isolate scope expect an attribute called value.
value: "=" means that you expect an attribute with tha name of value.
value: "=ngModel" means that you will have a property called value in your isolated scope linked to the ng-model attribute.
I give you here 2 examples:
http://jsbin.com/EyareCo/1/edit
The first one, just bind your bar with the internal scope via a value attribute. Works just fine.
The second one, uses ngModelController which is more advanced that the first one. The idea behind using ngModelController is to provide validation and more stuff.
You can just simply use scope.bar in all three cases
It would look like
{{bar}}
<input type="text" ng-model="bar">
<foo value="bar">
You shouldn't use ng-model in your directive, because you deal with the isolated scope hear, which contains only 'value' field.
The '=' binding that you've provided will do the rest of the job for you. When value changes through the ng-model from your input it will also change inside your directive
UPDATE:
To bind textarea with 'bar' value you should also use ng-model hear, but instead of 'bar' we should use 'value' hear, because as I write before, there is no scope.bar field here, but only scope.value field, but it directly binded with 'bar' property of parent scope from outside. So template will looks like : <textarea ng-model='value'></textarea>.
If you want to update value when some event happens (not-angular event), you should use $scope.$apply to notify that values have been changed.
Check this fiddle:
http://jsfiddle.net/TNySn/1/
Hear, when we click button, all 3 values changing because changeValue function wrapped in $scope.$apply function, and when we change textarea text, text-box and {{bar}} output are also change

how to pass a json as a string param to a directive

When I try to eval the below json form it gives me an error -
eval("{form: 'form' , nameToMatch: 'password1'}")
Why is the above form not valid ?
However the below works fine -
eval("{form: 'form'}")
I am trying to pass the above json as a string, as a param input to a directive.
Below is the html -
<input type="password" name="password2" ng-model="user.confirmPassword" placeholder="Confirm Password" match="{form: 'form', nameToMatch: 'password1'}" required="required"/>
Thanks,
Murtaza
Put parens around your json:
eval("({form: 'form' , nameToMatch: 'password1'})")
Doesn't seem like an angular question though. Not sure what you're trying to do:
Anyhow, to pass the json to the directive there are lots of ways to do that. I'm not sure why you'd want to do that and not just pass an object though.
passing json can be done a lot of ways...
From your attributes object:
app.directive('foo', function () {
return function(scope, element, attrs) {
var obj = eval('(' + attrs.foo + ')');
};
});
where
<div foo="{'test':'wee'}"></div>
From an isolated scope:
app.directive('foo', function () {
return {
restrict: 'E',
scope: {
'jsonIn' : '#'
},
link: function(scope, element, attrs) {
var obj = eval('(' + scope.jsonIn + ')');
};
};
});
where
<foo json-in="{'test':'wee'}"></foo>
But it's by far better to avoid using the native eval at all costs, if you can. Which in almost all cases you can. If you have some data just put it in an object on a scoped parameter and pass it in either via a two-way property on an isolated scope, or by name and do an angular $eval on it.
EDIT: The pass an object in...
You could use two way binding on an isolated scope:
app.directive('foo', function (){
return {
restrict: 'E',
scope: {
'data' : '='
},
link: function(scope, elem, attrs) {
console.log(scope.data);
}
};
});
where
<foo data="{ test: 'wee' }"></foo>
The really cool thing about doing it this way, is if you're using a scoped property it will update bi-directionally:
app.controller('MainCtrl', function($scope) {
$scope.bar = { id: 123, name: 'Bob' };
});
where
<foo data="bar"></foo>
I hope that helps.
It looks like you are trying to confirm a password in a form. There are many ways that you can go about this without resorting to JSON to pass values around in AngularJS. The most useful resource I've found online is from this Google Group thread:
1) http://jsfiddle.net/pkozlowski_opensource/GcxuT/23/ will compare
value in a second field with model value of the first field
2)
http://jsfiddle.net/S8TYF/ will compare value in a second field with
input value of the first field
The difference might be subtle but has practical consequences: with
(2) the confirm validation will kick-in as soon as you start typing
anything in the first field. With (1) the confirm validation will
kick-in only after the first field is valid. In the e-mail confirm
example it means that you won't start showing confirmation errors till
e-mail validation errors are sorted out (so a user can focus on one
error at the time).
Source: https://groups.google.com/d/msg/angular/R4QeNsNksdY/migbplv8GxIJ
From the first link, the directive is used as follows:
<label>e-mail</label>
<input name="email" type="email" required ng-model="email">
<label>repeat e-mail</label>
<input name="emailRepeat" type="email" required
ng-model="emailRepeat"
ui-validate-equals="email">
Where the ui-validate-equals directive points to the email model that was defined in the first input.
There are some StackOverflow answers to this if you would like to look there as well for additional ideas to solve your problem.
See also. #Blesh has mentioned in passing, but not emphasized: Angular provides you with a 'safe'-ish version of eval(), which works perfectly for passing declarative objects/arrays into your directive if you don't want to declare them on your scope, and wisely don't want to use native eval(). In the OP's example, just use this inside the directive:
angular.$eval(attrs.match);
Doesn't seem like an angular question though.
Agreed - vanilla JS can handle this just fine.
// Markup (HTML)
<div mydirective='{"test1": "foo", "test2": "bar"}'></div>
// App (JS)
JSON.parse(attrs['mydirective']);
Use JSON.parse(string) in angular. be sure that your parameter is in string format.

Resources