AngularJS directive passing dynamic ui-sref - angularjs

I'm using the old AngularJS 1.5.11 in a large project and I'm trying to clean up my templates using directives.
I have an edit button directive in which I would like to pass through the ui-sref but when I do I get the error
Error: [$parse:syntax] Syntax Error: Token '}' not a primary expression at column 6 of the expression [{id: }] starting at [}].
Here is my directive
editButton = ->
return {
restrict: 'EA',
scope: {
sref: "#"
},
template: '
sref = {{sref}}
<button id="edit-btn"
class="mds__button -blue"
ui-sref={{sref}}>
<i class="fa fa-edit"></i> Edit
</button>
'
}
angular
.module('myApp')
.directive('editButton', editButton)
And here is how I call it
<edit-button sref="job_edit({id: {{job.id}}})" />
In my template I display the sref and it's correctly printed out but the button doesn't like the ui-sref.
Update
I got it working but it would be nice to refactor this so I pass the job_edit({id: job.id}) attribute and it works.
Directive;
editButton = ->
return {
restrict: 'EA',
scope: {
model: "#"
item: "="
},
template: '
<button id="edit-btn"
class="mds__button -blue"
ui-sref="{{model}}_edit({id: item.id})">
<i class="fa fa-edit"></i> Edit
</button>
'
}
angular
.module('myApp')
.directive('editButton', editButton)
Calling it in my templates;
<edit-button model="job" item="job" />

You can't make that sref = {{sref}} inside an Angularjs template.
When you declare sref on the scope object of the directive that means that your directive gets an isolated scope with sref property on it, with the value that was passed to the directive as an attribute.
This declaration has few possible values, such as, #, =, &.
# is used for an interpolation value, that means that whenever you pass a value to the attribute, you need pass some interpolation
<edit-button sref="{{somethingAvailableOnParentScope}}" />
= 2 way data binding, you need to pass some expression
<edit-button sref="somethingAvailableOnParentScope" />
& bind a function, used to pass a "pointer" to a function. (not relevant for our case)
To sum up, we want to pass the value of job_edit invokation to our directive, therefore we need to use =.
editButton = () => ({
restrict: 'EA',
scope: {
sref: "="
},
template: '
<button id="edit-btn"
class="mds__button -blue"
ui-sref="sref">
<i class="fa fa-edit"></i> Edit
</button>
'
});
angular
.module('myApp')
.directive('editButton', editButton)
And the usage will be something like that:
<edit-button sref="job_edit({id: job.id})" />

Related

How to access the attribute of angular directive in templateUrl html content

How do I access the attribute of angular directive in templateUrl html content?
angular.module('myApp')
.directive('questionImage', function () {
return {
restrict : 'E',
scope : false,
templateUrl : 'templates/questionImage.html',
link : function(scope, element, attrs) {
scope.type = attrs['type'];
}
}
});
template HTML:
<div>
<label>Image Links</label><br>
<button type="button" ng-click="newImageLink('{{type}}')">+</button>
<span ng-repeat="imageLink in questionFormData.imageUrls['{{type}}'] track by $index">
<input type="text" ng-model="questionFormData.imageUrls['{{type}}'][$index]">
<button type="button" ng-click="removeElement(questionFormData.imageUrls['{{type}}'], $index)">-</button>
</span>
</div>
Inside this HTML, I need to access the "type" attribute value specified when the directive is used in DOM such as below.
<question-image type="optionAImages"></question-image>
<question-image type="optionBImages"></question-image>
How do I get "type" attribute value inside the template html?
Update: Added the 'link' function in the directive definition. I was able to get the type but its value is always the last directive usage.
i.e I always see optionBImages value for type attribute. optionAImages value is not available.
the problem comes from the scope:false statement as as the second call of the question-image directive override the parameter changed by the first call of the same parameter
you need to change the scope:false to be scope:true
this will not create an isolated scope but it will give the directive a nested scope of the parent scope of the controller.
return {
restrict : 'E',
scope : {
type : '#'
},
templateUrl : 'templates/questionImage.html'
This is equivalent to
scope.type = attrs.type;

Acessing form from directive's link function

In my custom directive I'm declaring new form <div ng-form="inputForm"></div> with input in it.
How can I access to this form within link function? scope.inputForm is undefined:/
Edit: code sample
.directive('ifInput', ['$system', function ($system) {
return {
restrict: "E",
replace: true,
scope: {},
link: function (scope, element, attrs) {
scope.temp = function () {
console.log(scope.inputForm);
}
},
templateUrl: "template/if-input-pola/index.html"
};
}])
.run(["$templateCache", function ($templateCache) {
$templateCache.put("template/if-input-pola/index.html",
"<div ng-form=\"inputForm\" class=\"form-group ng-fadeInLeft\" ng-class=\"{'has-error': inputForm[kolumna.id].$invalid && inputForm.$dirty}\">" +
"{{inputForm|json}}"+ //here is correct object (with $error and so on)
"<a ng-click=\"temp()\">a</a>" + //here is undefined
"</div>"
);
}])
EDIT 2:
Problem was that I wan's using object like this ng-form="model.inputForm" - now everything is ok
You can just define ng-model e.g.
<input ng-model="myInput"> and
link: function (scope, element) {
console.log(scope.myInput);
}
According to the documentation, using ng-form="inputForm" should post the controller on the local scope. If you cannot see it, you're either looking at a nested scope with that property overwritten, or at an ancestor scope. Keep in mind, that some directives, such as ng-repeat or ng-if, create local scopes, so in the following code:
<div ng-controller="myController">
<div ng-if="someCondition">
<div ng-form="myInput">
...
</div>
</div>
</div>
myInput would NOT be visible on the scope managed by myController.
When accesing the scope property within a link function, it also depends where your linked directive is, as the property may not be assigned to the scope yet. Try $watching the property and you just might find out it's being assigned later.

Passing a parameter into a function bound through a template in Angularjs (disambiguation)?

I am learning from this site:
https://egghead.io/lessons/angularjs-understanding-isolate-scope
The example code does this:
js code:
// Some directive named kid defined here
.
.
.
template: '<input type="text" ng-model="chore">' +
' {{chore}}' +
' <div class="button" ng-click="done({chore:chore})">I\'m done!</div>'
.
.
.
html code:
<div ng-app="choreApp">
<div ng-controller="ChoreCtrl">
<kid done="logChore(chore)"></kid>
</div>
</div>
What is this ({key: value}) syntax? If I change either the key or the value the whole thing stops workinng. How do you use this correctly? What are the rules?
tl;dr
In the html:
<your-directive your-attribute="yourMethod(yourArg)">
<your-directive your-attribute="yourMethod(yourOtherArg)">
In the js:
scope: {yourAttribute: '&'}
template: '<div ng-click"yourAttribue({yourArg : whateverValueYouWantItToRepresent,
yourOtherArg : someValueYouAlsoWantToRepresent})">
Basically, it lets your replace predetermined 'keys' with any expression you desire. Not sure yet when that would be useful though. This does let you penetrate into the isolate scope.
the key:value notation is required for method arguments when passing a method to your directive. For example you might want to provide for a callback method to be executed when your directive element is clicked:
in controller:
$scope.aMethod = function(arg1) {
...
};
in HTML:
<div my-directive some-method="aMethod()">
directive:
.directive('myDirective', function(){
scope: {
aomeMethod: '&'
}
link: function (scope, elem, attrs) {
elem.bind('click', function (){
scope.someMethod({arg1: 123});
});
}
});
The method defined in the controller takes an argument. However when you pass the method to the directive via the html notice the empty parenthesis. The directive has no idea about these args or what they should be called hence the need to explicitly pass the arg key along with the value.

AngularJs : Passing parameter to ng-click in directive

I have a directive in which i am adding an a button and an ng-click on the button. My code for directive is
AppDirectives.directive(
'feed',
function() {
return {
restrict : 'AE',
scope : {
feedMsg : '#feedText',
feedUser : '#feedUser',
feedTimestamp : '#feedTimestamp',
feedLike : '#feedLike',
feedDislike : '#feedDislike',
likeClick: '&',
dislikeClick :'&',
feedUid : '#feedUid'
},
template : '<div class="media">'+
'<a class="pull-left" href="#"><img class="media-object" src="resources/images/holder.png" style="height:64px; width:64px;" alt="img"></a>'+
'<div class="media-body">'+
'<h4 class="media-heading">{{feedUser}}</h4>'+
'<h5>{{feedMsg}}</h5>'+
'<p> <a ng-click="likeClick(feedLike)">Like</a> {{feedLike}} <a ng-click="dislikeClick(feedUid)">Dislike</a> {{feedLike}} {{ feedTimestamp | date:medium }} </p>'+
'</div>'+
'</div>',
replace : true,
};
});
my html code is
<feed feed-uid={{feed.uid}} feed-text={{feed.feedText}} feed-user={{feed.userUid}} feed-timestamp={{feed.time}} feed-like={{feed.like}} like-click="likeClick(uid)" dislike-click="dislikeClick(uid)" feed-dislike={{feed.dislike}}></feed>
and my contoller have
$scope.dislikeClick = function(feedUid){
console.debug("dislike"+feedUid);
}
When i click on the dislike button, i get 'like undefined', where i am suppor to print the 'like uid_of_post'. can any one kindly tell me what is wrong with my code. As {{feedUid}} get the correct value inside the template.
from the documentation on $compile, which houses directive docs:
Often it's desirable to pass data from the isolated scope via an expression and to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).
So in this case you'd be doing ng-click="dislikeClick({uid: feedUid})" and then from your html just do dislike-click="dislikeClick(uid)"
I'm answering to make this specific to your use case, but I think this is pretty much the same question as: AngularJS getting $event from a directive

exposing an object in angularjs directive scope, can't access properties

So, I have the following relatively simple Angularjs directive
app.directive('myDirective', function () {
return {
restrict: 'E',
scope: {
site: '#',
index: '#'
},
template: '<div>{{site}}</div>',
replace: true,
}
});
And here is where I call the directive in HTML
<div id="eventGraphic" class="span12">
<my-directive ng-repeat="site in IEvent.sites" site="{{site}}" index="{{$index}}"></my-directive>
</div>
Which, given that each site is an object, produces this output (copied from browser)
{"name":"Hurlburt","_id":"5148bb6b79353be406000005","enclaves":[]}
{"name":"Walker Center","_id":"5148cca5436905781a000005","enclaves":[]}
{"name":"test1","_id":"5148ce94436905781a000006","enclaves":[]}
{"name":"JDIF","_id":"5148cf37436905781a000007","enclaves":[]}
However, if I change the template in the directive to
template: '<div>{{site.name}}</div>',
it does not produce any output. This seems like a fairly straightforward use case, any ideas what I could be doing wrong? The desired output would be just the name field in each object.
You need to use '=' to map the object. '#' implies you're just passing a string value to the new scope.
app.directive('myDirective', function () {
return {
restrict: 'E',
scope: {
site: '=', //two-way binding
index: '#' //just passing an attribute as a string.
},
template: '<div>{{site}}</div>',
replace: true,
}
});
Then in your markup, don't use a binding in the attribute, just pass the expression:
<div id="eventGraphic" class="span12">
<!-- below, site="site" is passing the expression (site) to
the two way binding for your directive's scope,
whereas index="{{$index}}" is actually evaluating the expression
($index) and passing it as a string to the index attribute,
which is being put directly into the directive's scope as a string -->
<my-directive ng-repeat="site in IEvent.sites"
site="site"
index="{{$index}}"></my-directive>
</div>

Resources