How can one utilize a string contained within a variable as a template?
For example:
Controller
$scope.items = [
{
name: "Bruce Wayne"
},
{
name: "Lucius Fox"
}
];
$scope.template = "<input ng-model='item.name' type='text'>";
View
<div ng-repeat="item in items">
<div ng-bind-html="<!-- The `template` variable defined in the controller. -->">
</div>
</div>
I've tried $sce.trustAsHtml, which only doesn't connect with the actual scope when using things like ng-model='item.name'. Reading through the $sce docs I don't think that it provides anything that can trust a string as a template.
A fiddle for you to play with.
to actually bind data from ng repeat to input need to compile the html. for that this directive can be used
app.directive('dynamic', function($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, element, attrs) {
scope.$watch(attrs.dynamic, function(html) {
element[0].innerHTML = html;
$compile(element.contents())(scope);
});
}
};
});
<div ng-repeat="item in items">
<div dynamic="template">
</div>
</div>
$scope.items = [
{
name: "Bruce Wayne"
},
{
name: "Lucius Fox"
}
];
$scope.template = "<input ng-bind='item.name' type='text'>";
Demo
Related
I am trying to pass a scope array element to a directive and changing the value of that element inside the directive but when I print the values of the scope element the changes that made inside the directive is not affected in the parent scope. I created Isolated scope and provided two way binding using '=' in scope but It is not giving any change in the parent scope.
Attaching the code
Index.html
<div ng-app="dr" ng-controller="testCtrl">
<test word="word" ng-repeat="word in chat.words"></test>
<button ng-click="find();">
click
</button>
</div>
Javascript Part
var app = angular.module('dr', []);
app.controller("testCtrl", function($scope) {
$scope.chat= {words: [
'first', 'second', 'third'
]};
$scope.find = function(){
alert(JSON.stringify($scope.chat, null, 4));
}
});
app.directive('test', function() {
return {
restrict: 'EA',
scope: {
word: '='
},
template: "<input type='text' ng-model='word' />",
replace: true,
link: function(scope, elm, attrs) {
}
}
});
Most of my search returned that putting '=' in directive scope will solve the issue, But no luck with that. can anyone point what is the issue, and how can I reflect the value in parent scope.
You pass a string to your directive, and this string isn't referenced because its not related to your array anymore
i guess you have to change your array properly
Something like the following should work:
var app = angular.module('dr', []);
app.controller("testCtrl", function($scope) {
$scope.word = 'test';
$scope.chat= {words: [
{'name':'first'}, {'name': 'second'}, {'name' : 'third'}
]};
$scope.find = function(){
alert(JSON.stringify($scope.chat, null, 4));
}
});
app.directive('test', function() {
return {
restrict: 'EA',
scope: {
word: '='
},
template: "<input type='text' ng-model='word.name' />",
replace: true,
link: function(scope, elm, attrs) {
}
}
});
<div ng-app="dr" ng-controller="testCtrl">
<pre>{{chat.words}}</pre>
<test word="word" ng-repeat="word in chat.words"></test>
<button ng-click="find();">
click
</button>
</div>
The directive can be made more efficient by using one-way (<) binding:
app.directive('test', function() {
return {
restrict: 'EA',
scope: {
̶w̶o̶r̶d̶:̶ ̶'̶=̶'̶
word: '<'
},
template: "<input type='text' ng-model='word.name' />",
replace: true,
link: function(scope, elm, attrs) {
}
}
});
One-way (<) binding has the additional advantage that it works with the $onChanges life-cyle hook.
I am trying to create a few different directives that will work as search / filter tools for different parts of my application.
For this purpose i have created the following directive code:
app.directive("lbFilterDivision", ['divisionService', function (divisionService) {
return {
restrict: "E",
templateUrl: 'tpl/directives/lb-filters/lbFilterDivision.html',
scope: {
model: '='
},
link: function (scope, element, attr) {
scope.divisions = [];
divisionService.getList().then(function (result) {
scope.divisions = result;
})
}
};
}]);
The template attached to this is:
<select class="form-control"
ng-model="model"
ng-options="item.id as item.name for item in divisions"
fix-select-null="">
<option value="" translate="FORMS.DIVISION_PLACEHOLDER"></option>
Okay first of all let me explain the main idea.
The idea is that you have a search variable that will be passed to the directive. Then the two way binding should notify up through the system.
So say for instance i have the following HTML:
<lb-filter-division model="search.division.id"></lb-filter-division>
<li ng-repeat="user in users | filter:search"> </li>
As you can see i set the model = to search.division.id which means every time i change selected variable it should update the search.division.id variable and filter the list.
Sadly this is not the case.
Can anyone see what ive done wrong?
Edit - I found the answer. Apprently there was a syntax error in my code. Im so sorry! i will leave this code here if someone gets the same idea as my self.
Here is a fiddle:
fiddle
Solved the problem.
If you wish to copy or are looking to solve the same issue i can refer to this fiddle i made:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.users = [
{id: 1, name: "div1", division:{id: 1, name: 'hello'}},
{id: 2, name: "div2", division:{id: 2, name: 'hello2'}},
{id: 3, name: "div3", division:{id: 3, name: 'hello3'}}
]
}
myApp.directive("lbFilterDivision", function () {
return {
restrict: "E",
scope: {
model: '='
},
template: '<select ng-model="model" ng-options="item.id as item.name for item in divisions"></select>',
link: function (scope, element, attr) {
scope.divisions = [{id: 1, name:'hello'},{id: 2, name:'hello2'},{id: 3, name:'hello2'}];
}
};
});
fiddle
Good luck!
I want to pass object array to directive and have it print out the fields which I determine at the place where I use that directive.
Here's the example:
//directive
app.directive('MyDirective', function() {
return {
restrict: 'A',
templateUrl: 'my-directive.html',
scope: {
items: '#',
field: '#'
}
};
});
// my-directive.html template
<div ng-repeat="item in items">{{ item.field }}</div>
The idea is that I could use it with any object like this:
// object arrays
var phones = [{id:1,number:'555-5555'}, {id:2,number:'555-6666'}];
var persons = [{id:1,name:'John'}, {id:2,name:'Jane'}];
// directive usage
<div my-directive items="phones" data-field="???number???"></div>
<div my-directive items="persons" data-field="???name???"></div>
The result should print out numbers and names. Is that even doable in Javascript?
You can, just bind the items with '=':
.directive('myDirective', function() {
return {
restrict: 'A',
template: '<div ng-repeat="item in items">{{ item[field] }}</div>',
scope: {
items: '=',
field: '#'
}
};
})
Then use it like this:
<div my-directive items="phones" field="number"></div>
See this plunker.
Yes, it's possible, you can do it like this:
Directive:
myApp.directive('myDirective', function() {
return {
restrict: 'A',
template: '<div ng-repeat="item in items">{{ getItemField(item) }}</div>',
scope: {
items: '=',
field: '#'
},
link: function(scope, element, attr) {
scope.getItemField = function (item) {
return item[scope.field];
};
}
};
HTML:
<div my-directive items="phones" data-field="number"></div>
<div my-directive items="persons" data-field="name"></div>
Fiddle
This doesn't take a directive, probably the directive you are looking for is ng-repeat:
var phones = [{id:1,number:'555-5555'}, {id:2,number:'555-6666'}];
var persons = [{id:1,name:'John'}, {id:2,name:'Jane'}];
<li ng-repeat="phone in phones">{{phone.number}}</li>
<li ng-repeat="person in persons">{{person.name}}</li>
I am new at angularjs and I want to create a directive to change text for human readable.
scope including records coming from database. I want to change them matching humanReadable array.
angular.module('app', [])
.directive("humanReadable", function () {
return {
restrict: "A",
replace: true
}
});
var humanReadable= [{
text: "first_name",
replace: "First Name"
},
{
text: "last_name",
replace: "Last Name"
}];
function MyCtrl($scope) {
$scope.comesFromDatabase = ["first_name", "last_name"];
}
my html is like this.
<div ng-app="app">
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in comesFromDatabase">{{item}} -
<span human-readable="item"></span>
</li>
</ul>
</div>
</div>
and jsfiddle is here
As Martinspire mentioned, it's better to use a filter which might look something like below -
angular.module('myapp')
.filter('humanReadable', [function () {
return function (str) {
return str.split("_").join(" ").replace(/([^ ])([^ ]*)/gi,function(v,v1,v2){ return v1.toUpperCase()+v2; });
};
}]);
If you want directive only, with a bit of modification for the above code, it looks like this -
angular.module('myapp')
.directive('humanReadable', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.html(attrs.humanReadable.split("_").join(" ").replace(/([^ ])([^ ]*)/gi,function(v,v1,v2){ return v1.toUpperCase()+v2; }));
}
};
});
Edit: I have done it without using your humamReadable array to generalize it assuming that you might find it useful instead of using a separate array.
angular.module('app', [])
.directive("humanReadable", function () {
return {
restrict: "A",
scope: {
items: '=',
humanReadable: '='
},
link: function (scope, element, attrs) {
scope.items.forEach(function (item, i) {
if (item.text === scope.humanReadable) {
element.text(item.replace);
}
});
}
}
});
Demo: http://jsfiddle.net/vhbg6104/4/
A better way would be to use a custom filter. You can read all about it in the docs https://docs.angularjs.org/guide/filter or api https://docs.angularjs.org/api/ng/filter/filter
You could take some inspiration from the translate-filters too: https://github.com/angular-translate/angular-translate
In summary, you would probably write it like so: {{item | human-readable}} or with ng-bind like so: <span ng-bind="item | human-readable">
Use the tools and i'm sure you can figure something out
I need some help with getting AngularJS to maintain my non-string values in directive attributes.
I was looking for a way to render a tree structure in HTML from a piece of JSON, and I found this code: http://jsfiddle.net/n8dPm/
I've been trying to adapt that for my project, as shown in the code below.
My controller/directive is shown here:
cxpControllers.controller("ProductTocCtrl", ["$scope", "$http", "$routeParams",
function ProductTocController($scope, $http, $routeParams) {
$scope.typeOf = typeOf;
//test value
$scope.contents = {
"id": 1,
"name": "Test",
subsections: [
{
id: 2,
name: "Test1.1",
link: "test11.xml",
test: 34
},
{
id: 3,
name: "Test1.2",
link: "test12.xml",
test: 95
}
]
}
}]);
cxpControllers.directive('tree', function($compile) {
return {
restrict: 'E',
scope: {key: "=", content: "="},
templateUrl: "tree_renderer.html",
compile: function(tElement, tAttr) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
And then this is my template:
<script type="text/ng-template" id="tree_renderer.html">
{{key}}:
<ul ng-if="typeOf(content) == 'object' && content != null">
<li ng-repeat="(key, content) in content">
<tree key="key" content="content"></tree>
</li>
</ul>
<span ng-if="typeOf(content) != 'object'">
"{{content}}"
</span>
</script>
<ul>
<li ng-repeat="(key, content) in contents">
<tree key="key" content="content"></tree>
</li>
</ul>
This would work, except for one problem. Angular is turning the value of "content" into a string, preventing the recursion from working because it can't iterate over a string.
I have seen other questions like this, for example here, but their problem is that they used "#" in the directive scope, which converts to a string. But since I'm using "=", it should maintain the type.
Here's the output I'm seeing with the test data shown in the code above:
I would appreciate any help you can give. If you need more information I'll be happy to supply it.
The problem is with the typeOf function in your template. The compiled template doesn't find this function so it is never equal to 'object'. Add a controller to your directive to define it.
I took the plunkr and added this:
controller: function($scope) {
$scope.typeOf = function(val) {
return typeof val;
};
},
It does recognize it as an object. Check out the updated plunkr here.