Reputation: 4294
ng-repeat
.dropdown-list
directive from the array of objects like {title: "Link title", href: "/some-href"}
.I need to pass dynamic parameters for ng-href
(project.id
in my case), into my directive's template, which I use in ng-repeat
. How can I achieve that?
That is my general question. I feel like I have significant misunderstanding of Angular JS concepts here and counting on your help.
I've tried passing array of strings into my directive, and I got unparsed href like this:
/projects/%7B%7B%20project.id%20%7D%7D/edit
Why is that?
<li ng-repeat="project in data.projects">
<a ng-href="/projects/{{ project.id }}">{{ project.title }}</a>
<a dropdown-list="projectContextMenu"></a>
$scope.projectContextMenu = [
{
text: "Edit",
href: "/projects/{{ project.id }}/edit"
}, {
text: "Delete",
href: "/projects/{{ project.id }}/delete"
}
];
passing a function returning an array of parsed strings, but got an endless recursion error:
10 $digest() iterations reached. Aborting!
How come?
<li ng-repeat="project in data.projects">
<a ng-href="/projects/{{ project.id }}">{{ project.title }}</a>
<a dropdown-list="projectGetContextMenu(project.id)"></a>
$scope.projectGetContextMenu = function(projectID){
return [
{
text: "Edit",
href: "/projects/" + projectID + "/edit"
}, {
text: "Delete",
href: "/projects/" + projectID + "/delete"
}
];
}
angular.module("ngDropdowns", []).directive("dropdownList", [
"$compile", "$document", function($compile, $document) {
var template;
template =
"<ul>"+
" <li ng-repeat='dropdownItem in dropdownList' ng-class='{ \"active\": dropdownModel && dropdownModel.value == dropdownItem.value }'>"+
" <a href='' ng-href='{{ dropdownItem.href }}' ng-click='itemSelect(dropdownItem)'>{{ dropdownItem.text }}</a>"+
"</ul>";
return {
restrict: "A",
replace: false,
scope: {
dropdownList: "=",
dropdownModel: "="
},
controller: [
"$scope", "$element", "$attrs", function($scope, $element, $attrs) {
var $template, $wrap;
$template = angular.element(template);
$template.data("$dropdownListController", this);
$element.addClass("dropdown_selected").wrap("<div></div>");
$wrap = $element.parent();
$wrap.append($compile($template)($scope));
$scope.itemSelect = function(dropdownItem) {
if (dropdownItem.href) {
return;
}
angular.copy(dropdownItem, $scope.dropdownModel);
$wrap.removeClass("dropdown__active");
};
$document.find("body").on("click", function() {
$wrap.removeClass("dropdown__active");
});
$element.on("click", function(event) {
event.stopPropagation();
$wrap.toggleClass("dropdown__active");
});
$wrap.on("click", function(event) {
event.stopPropagation();
});
}
]
};
}
])
Upvotes: 1
Views: 1623
Reputation: 48167
Your second approach is more correct because you need to construct different URLs based on the context. But like you saw, you get into an endless digest cycle.
This is because you are returning a different array reference every time
Angular sees it as being different, so requires another turn of the crank, which calls your function again, which returns a new array, etc, etc.
Your projectGetContextMenu
function needs to cache the results, and return the same reference. Like this:
var contextMenus = {};
$scope.projectGetContextMenu = function(projectID){
if(!contextMenus[projectId]) {
contextMenus[projectId] = [
{
text: "Edit",
href: "/projects/" + projectID + "/edit"
}, {
text: "Delete",
href: "/projects/" + projectID + "/delete"
}
];
}
return contextMenus[projectId];
};
Upvotes: 1