Set Id Attribute of element to variable from directives controller - angularjs

Update #2:
Sometimes using template: '<div id="{{vm.divId}}"></div>' works fine and the variable is input into the template and other times it doesn't work and instead of using the variable the ID is set to id="{{vm.divId}}". I still haven't figured out what is making it work sometimes and not others
Original Post
I have a simple directive that needs an element in the template to have the ID set dynamically. I figured this would be simple but no matter what I do the variable doesn't interpolate.
I have tried setting the ID like this, template: '<div id="{{vm.divId}}"></div>' like this template: '<div ng-attr-id="{{vm.divId}}"></div> and a number of variations of the two but none seem to work.
Here is the directive:
.directive('gMap', function() {
return {
restrict: 'E',
scope: {
'options': '='
},
transclude: true,
controllerAs: 'vm',
bindToController: true,
controller: function(mapService) {
console.log(this.options.mapId); // This logs the specified ID
this.divId = this.options.mapId;
},
template: '<div id="{{vm.divId}}"></div><div ng-transclude></div>'
};
})
Update:
I cut and paste my code into plunkr and it works fine there so it must be something else outside this directive but I have no idea where to start

Related

AngularJS directive with isolate scope, ng-repeat, and controllerAs

function directive() {
return {
restrict: 'E',
template: '<button ng-repeat="x in j.array" ng-click="j.set(x)">{{x}}</button>',
replace: true,
//scope: {},
bindToController: {
array: '=',
answer: '='
},
controller: function() {
var j = this;
j.set = function(data) {
j.answer = data;
};
},
controllerAs: 'j'
};
}
When I uncomment scope and create an isolate scope the directive no longer works. I'm trying to determine why.
Normally I still have access to the controllerAs in an ng-repeat, in this example when I lose it it's still available on $parent.j. I think there are 3 solutions.
Solution 1 is to leave it not in isolate scope.
Solution 2 would be to convert every reference to j inside the repeat to $parent.j.
Solution 3 is that there is some way to use j without having to use $parent that I'm unaware of.
It may be to do with the replace: true. If you wrap the button in a div, it seems to work! I've made a little Plunker here to demonstrate.

Nested Directives and NgModel

I feel like I'm missing a fundamental concept of Angular directives.
Referring to this Plnkr: http://plnkr.co/edit/WWp9lB6OvxHL8gyBSU5b?p=preview
I have a model of:
{
message: string,
value: number
}
And I have an itemEditor directive to edit that model:
.directive('itemEditor', function() {
return {
replace: true,
templateUrl: 'item.editor.html',
require: 'ngModel',
model: {
item: '=ngModel'
}
};
})
But I want to delegate the editing of value to a custom control:
.directive('valuePicker', function() {
return {
replace: true, // comment this to make it work
templateUrl: 'value.picker.html',
require: 'ngModel',
scope: {
ngModel: '='
},
controller: Controller
};
function Controller($scope, Values) {
$scope.values = Values;
console.log({scope:$scope});
}
})
At current, this code gives the error:
Error: $compile:multidir
Multiple Directive Resource Contention
Commenting the replace: true will allow this code to work. However, I lose the styling instructions from the parent template. I.E: the class form-control is not merged onto the select element.
What is the angular way to make this work?
You are calling value-picker twice here
<value-picker class="form-control" style="width:100%" name="item" value-picker ng-model="item.value"></value-picker>
The value-picker element contains value-picker attribute as well, both being treated as directive which in conflict causing multiple directive error. Remove the attribute value-picker, either call it as element or attribute. Or you can restrict the directive to a specific declaration.
Also remove ng-model from select element of value.picker.html template, which is causing another error:
Multiple directives [ngModel, ngModel] asking for 'ngModel'
So replace: true replaces and appends the current directive attributes to the root level of template element (in your case its select)
Updated Plnkr

AngularJS directive retaining original content

I'm totally confused on transclude/replace and directives. I thought I understood but now I'm lost on how to get this particular test case working. From everything I've in the docs, SO, and blogs, it seems like my code below should work. First, some code:
The markup:
<my-directive><h1>My Title</h1></my-directive>
The end result I want:
<my-directive><div class="awesome"><h1>My Title</h1></div></my-directive>
The directive:
myApp.directive('myDirective', function() {
return {
restrict: 'E',
transclude: true,
template: '<div class="awesome"></div>'
}
});
Instead of what I want, I get:
<my-directive><div class="awesome"></div></my-directive>
What am I doing wrong?
To place the transcluded content into the div, add the ng-transclude directive to it...
template: '<div class="awesome" ng-transclude></div>'
Demo - Fiddle
You are missing the "ng-transclude" in the directive template:
<div class="awesome" ng-transculde></div>

Angular: How to get content from a custom div

I want to get a the content from a custom div tag, I tried various ways to do it, not working well. Here is an example. The general item is to retrieve the content in the custom directive tags. and then bind them into the template. I hope some one can give me a suggestion or solution that does it, or does similar things
The html
<questions>
<qTitle> this is title</q-title>
<qContent> this is content <q-content>
</questions>
The angular js
var app = angular.module('app'[]);
app.directive('questions', function () {
return {
transclude: true;
template: "<div class='someCSSForTitle'>{{qTitle}}</div>"+
"<div class='someCSSForContent'>{{qContent}}</div>"
link:(scope, element, attrs)
scope.qTitle = element.find(qTitle).innerHTML
scope.qContent = element.find(qContent).innerHTML
}
}
});
First I'd advise you to read the AngularJS Guide. You didn't even copy-paste the structure correctly and you have javascript and even html errors.
Basic fixes:
HTML
<questions>
<q-title>this is title</q-title>
<q-content>this is content</q-content>
</questions>
Why do you mix qTitle and q-title?
As regarding JS:
app.directive('questions', function () {
return {
restrict: 'E',
replace: true,
template: "<div class='question'>{{title}}</div>", /* simplified */
link: function(scope, element, attrs) {
scope.title = "hallo";
console.log(element.html());
}
};
});
by default, restrict is set to 'A'. That means attributes. Your syntax is for elements.
replace set to true is not compulsory. However, because the browser doesn't understand your elements but does understand the content ("this is title"), it will print it.
the link function has to be a function. you had syntax errors there (same for transclude: you had something that you were not using followed by ";")
You can print the element to know the contents. If you do, you'll see that element in link is not question.
Now if you want to read the content, you can use a transclude function or create directives for each part and create the template separately. This seems simpler. Live example:
app.directive('questions', function () {
return {
restrict: 'E',
transclude: true,
replace: true,
template: "<div class='question' ng-transclude></div>",
};
});
app.directive('qTitle', function () {
return {
restrict: 'E',
transclude: true,
replace: true,
template: "<div class='title' ng-transclude></div>",
};
});
In this case you translude the contents to an inner div.
You can also define custom complex transclude functions in the compile phase but this doesn't seem necessary here.

AngularJS what does locals in directive stand for

AFAIK this is not documented, but I found in angular source a locals attribute in a directive example:
angular.module('transclude', [])
.directive('pane', function(){
return {
restrict: 'E',
transclude: true,
scope: 'isolate',
locals: { title:'bind' },
template: '<div style="border: 1px solid black;">' +
'<div style="background-color: gray">{{title}}</div>' +
'<div ng-transclude></div>' +
'</div>'
};
});
What does it do? How can I use it?
EDIT
to be more precise:
How can I access locals from directive's controller or linking function?
How can I dynamicly change locals from directive's controller or linking function?
Can I use locals in every directive, or does it have to be a directive with a transclude=true ?
The example code is on the ngTransclude page, inside the script.js tab.
I believe this is just the older syntax (which still seems to work). The newer syntax would replace
scope: 'isolate',
locals: { title:'bind' },
with
scope: { title: '#' },
I just want to close this question.
So the answer is like #ArunPJohny said
#param {Object=} locals (Optional object).
If preset then any argument names are read from this object first, before the $injector is consulted

Resources