Angular js : How to use link function to set value in directives - javascript

I created directives for form input controls.
function textControlDir()
{
return {
transclude: true,
restrict: 'E',
scope: {
data: '=data',
default: '=default'
},
template: "<div ng-transclude></div><label>{{data._text}} </label><input ng-model='answer.PC' type='text' name='{{data._attributeName}}' id='{{data._attributeName}}' value='{{default}}' >"
,
link: function (scope, element, attrs)
{
console.log('default');
console.log(scope.default);
}
};
}
Html
<div ng-if="que.QuestionData._fieldType === 'text'" >
<text-control-dir data="que.QuestionData" default="{{answers[que.QuestionData._attributeName]}}"></text-control-dir>
</div>
Here for input box I want to set value. that would be as per condition.
In link function of directive i am trying to write like
link: function (scope, element, attrs)
{
if(scope.default == ''){
scope.default = que.QuestionData._pageAttributes.defaultValue
}
}

As you have suggested that you have a E element directive, so you can make use of attrs param of link function:
link: function (scope, element, attrs){
if(attrs.default == ''){
attrs.default = que.QuestionData._pageAttributes.defaultValue
}
}
(function() {
var app = angular.module('demoApp', []);
app.controller('demoController', [demoController])
.directive('textControlDir', [textControlDirective])
function demoController() {}
function textControlDirective() {
return {
restrict: 'E',
template: "<div ng-transclude>::::textControlDirective::::</div>",
link: function(scope, element, attrs) {
console.log(attrs.default);
}
};
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<div ng-app='demoApp' ng-controller='demoController'>
<text-control-dir data="dataAttr" default="defaultAttr"></text-control-dir>
</div>

Related

AngularJS - Why I cannot get element class name in directive's link function?

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) {
},
}

AngularJS =?bind not updating

I've lost my bearings with regards to why I can't pass updates to my directives.
What I'm trying to accomplish with the following piece of code is to be able to set focus on by pressing a button. The problem is however that the "focus" binding on drInput only ever is set when the directive have loaded when it should change whenever it changes in drWrap. How come and how do I get around this?
And now, ladies and gentlemen, I present to you: THE CODE!
<div ng-app="myApp">
<dr-wrap></dr-wrap>
</div>
var myApp = angular.module('myApp', []);
myApp.directive('drWrap', function($timeout) {
return {
scope: {
focus: '=?bind'
},
restrict: 'E',
replace: 'true',
template: '<div><button ng-click="openSearch()">focus</button><dr-input focus="focusSearch" /></div>',
link: function(scope, elem, attr){
scope.openSearch = function(){
$timeout(function(){
scope.focusSearch = true
alert('scope.focusSearch 2 = ' + scope.focusSearch)
}, 1000)
}
}
};
})
.directive('drInput', function() {
return {
scope: {
focus: '=?bind'
},
restrict: 'E',
replace: 'true',
template: '<input type="test" focus-me="{{ focus }}" />',
link: function(scope, elem, attr){
scope.$watch('focus', function(value){
if(value != undefined){
scope.focus = value
alert('scope.focus = ' + scope.focus)
}
})
}
};
})
.directive('focusMe', ['$timeout', function ($timeout) {
return {
link: function (scope, element, attrs) {
attrs.$observe('focusMe', function(value){
if ((value === true) || (value == 'true')) {
$timeout(function () {
element[0].focus()
scroll(element[0])
})
} else {
element[0].blur()
}
})
}
}
}])
And the FIDDLE!
https://jsfiddle.net/L56rdqLp/168/
When you write scope: { focus: '=?bind' }, this means that the attribute name should be bind but not focus, so the template of drWrap should look like:
template: '<div><button ng-click="openSearch()">focus</button><dr-input bind="focusSearch" /></div>'
Add ngBlur event handler to drInput directives input like:
template: '<input type="test" focus-me="{{ focus }}" ng-blur="focus = false"/>',
to change the model to false, when input has lost its focus.
Here is working fiddle.

Angular: how to bind to required/ngRequired

I have this directive which can be required or not. It can be used in two ways (as far as I know)
<my-foo required></my-foo>
or
<my-foo ng-required="data.value > 10"></my-foo>
So, because require and ngRequire are basically the same thing you would think that the directive could do this
HTML:
<my-foo ng-require="data.isRequired"></my-foo>
JS:
...
.directive('myFoo', function () {
return {
restrict: 'E',
scope: {
required: '='
}
...
DEMO
Well, nope, this doesn't work, scope.require is undefined. You actually have to change the scope definition to
scope: {
required: '=ngRequired'
}
So the question is what is the preferred way to handle both situation such that the value gets stored in scope.required ? Should I defined both or use attrs from the link function ?
There are basically 2 approaches you can pick:
1. Custom form element supporting ng-model
If you peek at the ng-required directive source code you'll find it only deals with ng-model controller:
restrict: 'A',
require: '?ngModel',
link: function(scope, elm, attr, ctrl) {
if (!ctrl) return;
attr.required = true; // force truthy in case we are on non input element
ctrl.$validators.required = function(modelValue, viewValue) {
return !attr.required || !ctrl.$isEmpty(viewValue);
};
attr.$observe('required', function() {
ctrl.$validate();
});
}
Thus if you custom directive supports ng-model you already have support for ng-required i.e.:
angular.module('test', [])
.directive('myInput', function(){
return {
restrict: 'E',
require: 'ngModel',
scope: true,
template: '<div><button ng-click="changeValue()">Change Value from: {{currentValue}}</button></div>',
link: function (scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.push(function(val){
if(!val){
return null;
}
return parseFloat(val, 10) * 100;
});
ngModelCtrl.$render = function() {
scope.currentValue = ngModelCtrl.$viewValue || 'No value';
};
scope.changeValue = function read(){
var newValue = Math.random();
if(newValue > 0.5){
ngModelCtrl.$setViewValue(newValue + "");
} else {
ngModelCtrl.$setViewValue(null);
}
ngModelCtrl.$render();
};
}
};
});
2. Wrap existing directive and pass ng-required:
angular.module('test', [])
.directive('myFormElement', function() {
return {
restrict: 'E',
scope: {
model: '=',
required: '='
},
template: '<div>Enter number: <input type="number" ng-model="data.number" ng-required="required"></div>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-init="data={value:'Initial', required: false}">
<form>
Is required: <input type="checkbox" ng-model="data.required">
<my-form-element required="data.required" model="data"></my-form-element>
</form>
</div>

Adding a class to a trustedValue AngularJS

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);
}
}
};

Passing HTML to a template inside Angular directive

I need the HTML in newValue to work but it seems to just spit out escaped charaters
.directive('ngLookup', function () {
return {
restrict: 'A',
scope : {
text : '='
},
template: '{{newValue}}',
link: function (scope, elem, attrs) {
scope.newValue = scope.text.replace(/test/g,'test');
}
}
})
My solution using the answer below:
.directive('ngLookup', function ($compile) {
return {
restrict: 'EA',
scope : {
text : '='
},
link: function (scope, elem, attrs) {
var txt = '<span>'+scope.text.replace(/test/g,'test')+"</span>";
var newElement = $compile(txt)(scope);
elem.replaceWith(newElement);
}
}
})
You will have to compile the HTML yourself with the $compile-Service.
Do something like:
.directive('ngLookup', function ($compile) {
return {
restrict: 'A',
scope : {
text : '='
},
link: function (scope, elem, attrs) {
var newElement = $compile('test')(scope);
elem.replaceWith(newElement);
}
}
})

Categories

Resources