How do I replace an Angular attribute that already has a value in it? For example:
angular.module('app', [])
.directive('edit', function(){
return {
template: '<a ng-href="{{data}}">Link Text</a>',
replace: true,
link: function(scope, elm, attr){
scope.data = 'http://www.example.com';
}
};
});
HTML:
<a edit ng-href="test"></a>
That just appends the link url to the "test" href. I tried using
elm.attr('ng-href', '{{data}}');
and many variations on that idea, but it didn't work.
You can use compile function in directive, and redeclare this attribute in it:
.directive('edit', ['$timeout', function($timeout) {
return {
template: '<a ng-href="{{data}}">Link Text</a>',
replace: true,
restrict:'A',
compile:function(elm, attr){
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
iAttrs.ngHref = "{{data}}";
},
post: function postLink(scope, iElement, iAttrs, controller) {
scope.data = 'http://www.example.com';
}
}
}
}
}])
http://plnkr.co/edit/lBA9xR1VbWHqHbc5KG7w?p=preview
Related
Before setting the compiled html to dynamic-html div, my dynamicHtml is working correctly. As you can see, there's a onClick function in directive.
But unfortunately, after setting compiled html to div, onClick is not called anymore.
var content = $compile(res)($scope);
$('dynamic-html').html(content);
My dynamicHTML directive looks like this:
.directive('dynamicHtml', function($compile, $timeout) {
return {
restrict: 'E',
transclude: true,
link: function($scope, $element) {
$scope.datePickers = {};
$scope.onClick = function (variable, $event) {
var currentTarget = $event.currentTarget;
$scope.$parent.$parent.highlight(variable, true, currentTarget);
};
I tried to add transclude on directive as you can see. But it's not working on this case.
Can you please guide me to solve this problem?
Check it out the following code,
angular.module("myApp", [])
.directive("compiled", function($compile){
return {
restrict: "AE",
scope: {},
link: function(scope, ele, attrs){
var compiled = $compile("<div><hello-world></hello-world></div>")(scope);
ele.replaceWith(compiled);
}
}
})
.directive("helloWorld", function(){
return {
restrict: "AE",
scope: {},
transculde: true,
link: function(scope, ele, attrs){
scope.sayhello = function(){
alert("Hello World");
}
},
template: '<button ng-click="sayhello()">Say Hello</button>'
}
})
Html
<compiled></compiled>
I got below code. I expect it will show me true. However, it show me false.
Can anyone explain it to me and provide me a solution to check if the class existed in the element? Thanks in advance.
// HTML
<tit-txt class="{{editable}}" ng-model="mdEnt.phone"></tit-txt>
//JS
.directive('titTxt', function () {
return {
restrict: 'E',
scope: {
ngModel: '=',
},
link: function (scope, element, attrs) {
console.log(element.hasClass('editable'));
},
template: '<input ng-model="ngModel" />',
};
})
Use a watcher to detect when the class is updated:
app.directive('titTxt', function () {
return {
restrict: 'E',
scope: {
myModel: '=',
},
link: function (scope, element, attrs) {
scope.$watch(hasClassEditable, function() {
console.log(element.hasClass('editable'));
});
function hasClassEditable() {
return element.hasClass('editable');
}
},
template: '<input ng-model="myModel" />',
};
})
Interpolated bindings such as class={{editable}} update each digest cycle. The directive needs to wait for a binding to update before using the value.
The DEMO
angular.module("app",[])
.run(function($rootScope,$timeout) {
$rootScope.$timeout = $timeout;
})
.directive('titTxt', function () {
return {
restrict: 'E',
scope: {
myModel: '=',
},
link: function (scope, element, attrs) {
scope.$watch(hasClassEditable, function(value) {
console.log("has class 'editable'", value);
});
function hasClassEditable() {
return element.hasClass('editable');
}
},
template: '<input ng-model="myModel" />',
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<input type="checkbox" ng-model="editable" ng-change="$timeout()"
ng-true-value="'editable'" ng-false-value="''" />
add class "editable"
<br>
<tit-txt class="{{editable}}" my-model="inputTxt"></tit-txt>
<br>
editable="{{editable}}"
<br>
inputTxt="{{inputTxt}}"
</body>
Try to do it like this:
// HTML
<div ng-app="myApp" ng-controller="myController">
<tit-txt custom-class="customClass"
cust-var="myVal"></tit-txt>
<div ng-bind="myVal"></div>
</div>
//JS
var app = angular.module('myApp', []);
app.controller('myController', function($scope) {
$scope.customClass = "editable";
$scope.myVal = "this";
});
app.directive('titTxt', function () {
return {
restrict: 'AE',
replace: true,
scope: {
customClass: '=',
custVar: '='
},
link: function (scope, element, attrs) {
console.log(scope);
console.log((scope.customClass === "editable"));
},
template: '<input class="myClass" ng-Model="custVar"/>',
};
})
EDIT: Edited the code to include the working code. Here is the link for plunker
Try this instead:
link: function (scope, element, attrs, controller) {
console.log(angular.element(element).hasClass('editable'));
}
Try with pre function,
link: {
pre: function(scope, element, attr, controllers) {
console.log(element.hasClass('editable'));
},
post: function(scope, element, attr, controllers) {
},
}
I try to pass an attribute directive to an element directive, is it possible? I tried do it as in example but it doesn't work.
for example I have element directive:
<np-form-input
np-form-input-attrs="np-my-attr-directive"
>
</np-form-input>
JS:
.directive('npFormInput', [function () {
return{
restrict: 'E',
templateUrl: '/resources/view/common/form_input',
link: function(scope, element, attr){
scope.attributes= attr.npFormInputAttrs;
}
};
}])
And then in directive HTML
<input
{{attributes}}
>
Thanks in advance.
EDIT: My solution based on Micah Williamson answer:
.run(['$templateCache', '$http', function($templateCache, $http){
$http.get('/resources/view/common/form_input').success(function(data){
$templateCache.put('/resources/view/common/form_input', data);
});
}])
.directive('npFormInput', ['$templateCache', '$compile', function ($templateCache, $compile) {
return{
restrict: 'E',
compile: function (ele, attrs) {
var tpl = $templateCache.get('/resources/view/common/form_input');
tpl = tpl.replace('{{attributes}}', attrs.npFormInputAttrs);
var tplEle = angular.element(tpl);
ele.replaceWith(tplEle);
return function (scope, element, attr) {
$compile(tplEle)(scope);
};
},
};
}])
I've done something similar to what you're trying to do but I had to inject the attributes in the compile. You would need to add the template to $templateCache first though.
.directive('npFormInput', [function ($templateCache, $compile) {
return{
restrict: 'E',
compile: function(ele, attrs) {
var tpl = $templateCache.$get('/resources/view/common/form_input');
tpl = tpl.replace('{{attributes}}', attrs.npFormInputAttrs);
var tplEle = angular.element(tpl);
ele.replaceWith(tplEle);
return function(scope, element, attr){
$compile(tplEle)($scope);
};
}
};
}])
I want to get a value straight from an attribute directive:
<form cronos-dataset="People as p">
Form Content
</form>
In my JS I tried:
app.directive('cronosDataset',[function() {
return {
restrict: 'A',
controller: 'CronosGenericDatasetController',
scope: {
"cronos-dataset" : '#'
}
};
}])
.controller("CronosGenericDatasetController",['$scope', function($scope) {
alert($scope["cronos-dataset"]);
}]);
I want to alert "People as p" string but I get undefined. Is that right path or should I go thorough a different approach?
You are supposed to have camelCase in the scope declaration
app.directive('cronosDataset',[function() {
return {
restrict: 'A',
controller: 'CronosGenericDatasetController',
scope: {
cronosDataset : '#'
}
};
}])
Here is a demo to see different variations
http://plnkr.co/edit/G6BiGgs4pzNqLW2sSMt7?p=preview
Make a link function instead:
app.directive('cronosDataset',[function() {
return {
scope: {},
restrict: 'A',
link: function (scope, elem, attrs) {
alert(attrs.cronosDataset);
}
I have the following html:
<li class="editor" ng-model="post.text" ng-bind-html="post.text" add-class="post.text"></li>
where post.text is a wrapped trustedValue, that looks like this:
after I unwrap it, it looks like this:
Now, I want to make a directive, that searches that trustedValue, and adds a class to the img tags. So far I have this:
function AddClassToImg($sce) {
return {
restrict: 'A',
scope: {
addClass: '='
},
link: function (scope, elem, attrs) {
var content = scope.addClass.$$unwrapTrustedValue();
$(content).find('img').addClass('test');
}
}
};
angular.module('UserProfile')
.directive('addClass', ['$sce', AddClassToImg]);
How can I get the post.text from the html, two-way-bind to it, and add to all images in post.text that class?
I am just copying your code and adding logic to compile. Their might be slight modifications you might be required to do:
function AddClassToImg($sce,$compile) {
return {
restrict: 'A',
scope: {
addClass: '='
},
link: function (scope, elem, attrs) {
var content = scope.addClass.$$unwrapTrustedValue();
var imgElement = angular.element(content.querySelector('img'));
imgElement.addClass('test');
$compile(content)(scope);
}
}
};
angular.module('UserProfile')
.directive('addClass', ['$sce', AddClassToImg]);
I solved it, for everyone wondering the same thing, here is the code:
function AddClassToImg($sce, $compile){
return {
restrict: 'A',
scope:{
addClass: '='
},
link: function (scope, elem, attrs){
var content = scope.addClass.$$unwrapTrustedValue();
var newContent = $("<div>").append($(content).find('img').addClass('col-md-12 col-xs-12').end()).html();
scope.addClass = $sce.trustAsHtml(newContent);
}
}
};