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

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;

Related

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.

Function arguments in directive with templateUrl

I created a custom directive with an isolated scope that binds to a function from the enclosing controller and with references to a templateUrl. Here's what my code looks like:
the html
<div ng-controller='MyCtrl as my'>
<custom-directive data='my.data' on-search="my.find(param1, param2)"></custom-directive>
</div>
the directive
app.directive('customDirective', function() {
return {
restrict : 'E',
scope : {
data : '=data'
search : '&onSearch',
},
templateUrl : 'customDirective.html'
};
});
the template
<div>
<input ng-model='data.id'>
<a ng-click='find(param1, param2)'></a>
</div>
The arguments received by function find is also stored in data. The controller data binds to the directive but not the function. My log inside the function won't even show.
It seems there are different ways to do it as I have seen in many examples (see below) but none seems to work in my case.
Example 1: pass a mapping of parameter and values in the template
<div>
<input ng-model='data.id'>
<a ng-click='find.({param1: data.value1, param2: data.value2})'></a>
</div>
Example 2: put a link in the directive
app.directive('customDirective', function() {
return {
restrict : 'E',
scope : {
data : '=data'
search : '&onSearch',
},
templateUrl : 'customDirective.html',
link : function(scope, elem, attr) {
scope.retrieve({param1: scope.data.value1,
param2: scope.data.value2});
}
};
});
Example 3 : use scope.$apply(), $parse in link but haven't tried this
Could someone show me how to do it and also explain to me the link part (I don't understand that part) and if you're feeling generous, show the working alternatives as shown by the examples. Thanks
You don't have to passe params for your function just the reference so in your html
<custom-directive data='my.data' on-search="my.find"></custom-directive>
and your template directive directly call
<div>
<input ng-model='data.id'>
<a ng-click='find(data.value1, data.value2)'></a>
</div>
I also suggest you to use $scope and not the controller. So in your controller define
$scope.data = {
id: 1,
value1: "value1",
value2: "value2"
}
$scope.find = function (param1, param2) {
//Your logic
}
And in your template put directly
<custom-directive data='data' on-search="find"></custom-directive>
I hope this answer to your question
About link this text from angular js doc is pretty clear I think
Directives that want to modify the DOM typically use the link option.
link takes a function with the following signature, function
link(scope, element, attrs) { ... } where:
scope is an Angular scope object. element is the jqLite-wrapped
element that this directive matches.
attrs is a hash object with key-value pairs of normalized attribute names and their
corresponding attribute values.
In our link function, we want to update the
displayed time once a second, or whenever a user changes the time
formatting string that our directive binds to. We will use the
$interval service to call a handler on a regular basis. This is easier
than using $timeout but also works better with end-to-end testing,
where we want to ensure that all $timeouts have completed before
completing the test. We also want to remove the $interval if the
directive is deleted so we don't introduce a memory leak.

Dynamically initialize a ng-model directive

I'm dynamically building a form with angular depending of the kind of input:
<div ng-controller="formController" ng-repeat="field in formFields" ng-switch="field.type">
<div ng-switch-when="text">
<!-- Something -->
</div>
<div ng-switch-when="dropdown">
<myDirective my-data="field.param" ng-model="field.model"></myDirective>
</div>
</div>
I've got two problems with my directive which builds a custom dropdown input:
Ng-model directive interprated the name field.model as plain text, whereas I would like the attributs ng-model="field.model" would be replaced by the value contained into field.model. Curly brackets don't seems to work here. Any idea?
How to let the ng-model value accessible both in my form controller, and into my custom directive's controller?
Exemple of a field object:
{
label : "Name",
model : "employeeName",
type : "dropdown",
param : {
dropdownArray : result,
dropdownName : 'Nom',
dropdownFieldValue : 'nameUUID',
dropdownVisibleValue : [ 'employeeSS', 'employeeName' ]
}
}
Then in my controller I should be able to access this dropdown value with: $scope.employeeName.
It sounds like you're accessing field.model via the attributes input parameter supplied to the link function in your directive. Instead, you should be accessing it via the scope variable.
link: function(scope, element, attributes) {
// attributes.ngModel will yield 'field.model'
// scope.ngModel will contain the actual value of field.model
}
If you don't explicitly define an isolate scope for your directive, then ng-model assigned to field.model should be available in your directive via the scope variable as I mentioned above.
scope: false // This is the default
// Define an isolate scope with field.model available through scope.ngModel
scope: {
ngModel: '='
}
Hope that helps.

Angular - condition, transclude

I've written a sample directive with a conditional content (component.html):
<div class="panel panel-default">
<div class="panel-heading">{{title}}</div>
<div class="panel-body">
<p ng-show="loadingVisible()" class="text-center">Loading...</p>
<div ng-show="!loadingVisible()" ng-transclude></div>
</div>
Directive code (component.js):
app.directive('component', function () {
return {
restrict : 'A',
transclude : true,
replace : true,
templateUrl : 'component.html',
require : '^title',
scope : {
title : '#',
loadingVisible : '&'
},
controller : [ '$scope', function ($scope) {
if (!$scope.loadingVisible) {
$scope.loadingVisible = function () {
return false;
};
}
} ]
};
});
The main use of this directive is something like this (sample.html):
<div component title="Title">
<div id="t"></div>
</div>
And the controller code (sample.js):
app.directive('sample', function () {
return {
restrict: 'A',
templateUrl: 'sample.html',
controller: [ '$scope', function ($scope) {
$('#id');
} ]
};
});
0
The problem is that the div aquired by using jQuery selector isn't visible. I guess it's because the loadingVisible method (conditional content) hides that div in the construction phase. So when the sample directive tries to get it it fails. Am I doing something wrong? What's the coorect resolution of this problem? Or maybe my knowledge of directives is wrong?
I'll appreciate any help :)
if you're trying to interact with the DOM (or the directive element itself), you'll want to define a link function. The link function gets fired after angular compiles your directive and gives you access to the directives scope, the element itself, and any attributes on the directive. so, something like:
link: function (scope, elem, attrs) {
/* interact with elem and/or scope here */
}
I'm still a little unclear about what your directive is trying to accomplish though, so it's tough to provide much more help. Any additional details?
so if you want to ensure that a title is specified, you can just check for the presence of the title scope var when the directive gets linked, then throw an error if it's not there.
also, is there any reason loadingVisible needs to be an expression? (using '&' syntax). If you just need to show/hide content based on this value, you could just do a normal one-way '#' binding. so overall, something like:
app.directive('component', function () {
return {
restrict : 'A',
transclude : true,
replace : true,
templateUrl : 'component.html',
scope : {
title : '#',
loadingVisible : '#'
},
link : function (scope, elem, attrs) {
if (!scope.title) {
throw 'must specify a title!';
}
if (!attrs.loadingVisible) {
scope.loadingVisible = false;
}
}
};
});
If you need to get access to any of your transcluded content, you can use the elem value that gets injected into your link function, like so:
elem.find('#a');
an (updated) working plnkr: http://embed.plnkr.co/JVZjQAG8gGhcV2tz1ImK/preview
The problem is that directive structure is like this:
<div component>
<div id="a"></div>
</div>
The directive is used somewhere like this:
asd
The test directive uses a "a" element in its controller (or link) function. The problem is that the test controller code is run before the div is transcluded and it cannot see the content :/ A simple workaround is that the component should be before the test directive. Do you have any other solutions to this problem?

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

Resources