Directive with same template but with dynamic content - javascript

HTML :
<div custDirective id="managerNames"></div>
<div custDirective id="empNames"></div>
Template.html
<div ng-repeat="name in names">
<ol><li>{{name}}</li></ol>
</div>
Directive link function :
if(attr.id === "name"){
scope.names = ["A","B","C","D"];
}else{
scope.names = ["E","F","G","H"];
}
I want to get the dynamic list based on the id attribute.i.e, If id is managerNames then my ng-repeat should repeat a,b,c,d else it should repeat e,f,g,h.
How to achieve this? I am using angular.js 1.2 version.

you can send an attribute to your link where it will check on the value you send to it and work accordingly to it
Here is an example :
//Directive
angular.module('yourModule').directive('directiveName',
function($parse) {
return {
restrict: 'E',
templateUrl: "your/template.html",
scope: {
check: '#',
},
link: function(scope, element, attrs) {
if(scope.check == "whatever"){
}
}
})
//HTML
<directive-name check="whatever"></directive-name>

Related

Angular ng-Model different view and value

My Question is similar to this link.
I want '%' symbol for view only, it should not effect to ngmodel.How can I format this.
I have a text box which will have percentage value, there is a calculation based on that value.So I want to display '%' for view only and ngmodel contrains only value. How can I.
you can use custom filter for percentage value
angular.module('percentageValueFilter', [])
.filter( 'titlecase', function() {
return function(input) {
if(isNaN(input)
return input;
else
return input + "%";
}
});
use this filter as shown below example in your html
{{ yourVale | percentageValueFilter }}
{{ 10 | percentageValueFilter }} // 10%
{{ 'test' | percentageValueFilter }} // test
You can try the following code:
var myApp = angular.module('myApp', []);
myApp.controller('myController', ['$scope', function($scope){
$scope.testNumber = {number:30};
}]);
myApp.directive('myDirective', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function(data) {
//convert data from view format to model format
return data.replace('%','');
});
ngModelController.$formatters.push(function(data) {
//convert data from model format to view format
return data+'%';
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<input my-directive type="text" data-ng-model="testNumber.number" /> <br/>
ng-model value: {{testNumber.number}}
</div>
You can create a directive that require ngModel and add a formatter.
angular.module('formatter').directive('percentageFormatter', () => {
return {
require: 'ngModel',
link: (scope, el, attrs, ngModel) => {
ngModel.$formatters.push(value => `${value} %`);
}
}
});
When you require the ngModelController you have to add it to the input element. It is important to give it a name too.

Angular 1 custom directive not executing

I have my directive defined as follows:
'use strict;'
angular.module('clientApp')
.directive('afterLast', ['$ocLazyLoad','$timeout',function($ocLazyLoad, $timeout){
console.log('entered directive');
return {
restrict: 'A',
link: function(scope, elem, attr){
if (scope.$last === true){
console.log('entered directive')
$timeout(function(){
$ocLazyLoad.load(['some files'])
})
}
}
}
}]);
And, I am using it as an attribute as follows:
<div ng-repeat="topicObject in module.topics track by $index" afterLast>
<div class="ft-section">
<div ng-repeat="learningPointObject in topicObject.learningPoints track by $index">
<div class="ft-page">
<h2 class="module-name" style="text-align: center;">{{module.name | capitalize:true}}</h2>
<h3 class="topic-name">{{topicObject.name | capitalize:true}}</h3>
<h4>{{learningPointObject.name | capitalize}}</h4>
<hr>
</div>
</div>
</div>
</div>
But my directive is not executing. Even the console.log statements inside and outside the link function are not working.
1. Am I using directives the correct way?
2. If yes, what could be the reasons for it not working?
In the HTML the directive name needs to be in kebab-case, not camelCase.
<!-- ERRONEOUS camelCase
<div ng-repeat="topicObject in module.topics track by $index" afterLast>
-->
<!-- USE kebab-case -->
<div ng-repeat="topicObject in module.topics track by $index" after-last>
For more information, see AngularJS Developer Guide - Directive Normalization
directive : for last watch of ng-repeat..
app.directive('afterLast',function(){
return {
restrict: 'A',
scope: {},
link: function (scope, element, attrs) {
if (attrs.ngRepeat) {
if (scope.$parent.$last) {
if (attrs.afterLast !== '') {
if (typeof scope.$parent.$parent[attrs.afterLast] === 'function') {
// Executes defined function
scope.$parent.$parentattrs.afterLast;
} else {
// For watcher, if you prefer
scope.$parent.$parent[attrs.afterLast] = true;
}
}
}
} else {
throw 'ngRepeatEndWatch: ngRepeat Directive required to use this Directive';
}
}
}
});
function call on last call
$scope.layoutDone = function () {
you want your desire data here
}
html
{{module.name | capitalize:true}}
{{topicObject.name | capitalize:true}}
{{learningPointObject.name | capitalize}}

Reuse directive multiplie times with dynamic attributes in another directive's template

What i want to do is to be able to use a directive with different attributes in the same ng-app. The main goal is to run different code when the directive's input (ng-model) changes.
This is what i have now:
app.directive('customInput',
function ($compile) {
var customInputDefinitionObject = {
restrict: 'E',
replace: true,
scope: {
ident: '#'
},
template: '<input type="text" >',
controller: 'customInputController',
compile: function (tElement, tAttrs) {
$('input').removeAttr('ident')
.attr('ng-model', tAttrs.ident)
.attr('ng-change', tAttrs.ident + 'Change()');
var elemLinkFn = $compile(tElement);
return function (scope, element) {
elemLinkFn(scope, function (clone) {
element.replaceWith(clone);
})
}
}
}
return customInputDefinitionObject;
});
It works well in html e.g.:
<custom-input ident="var1"></custom-input>
<custom-input ident="var2"></custom-input>
i'm going to get to input with different ng-model and ng-change function, the controller uses dynamic names to get the $scope variables( $scope.var1Change).
The problem start when i want to use this directive inside another template.
app.directive('customInputGroup', function ($compile) {
var customInputGroupDefinitonObject = {
restrict: 'E',
replace: true,
scope: {
rident: '#',
},
template:''+
'<div>'+
'<custom-input id="first"></custom-input>'+
'<custom-input id="second"></custom-input>'+
'</div>',
controller: 'customInputGroupController',
compile: function (elem, attrs) {
$('#first', elem).removeAttr('id').attr('ident', attrs.rident + 'Start');
$('#second', elem).removeAttr('id').attr('ident', attrs.rident + 'End');
var rangeLinkFn = $compile(elem);
return function (scope, element) {
rangeLinkFn(scope, function (clone) {
element.replaceWith(clone);
})
}
}
}
return customInputGroupDefinitonObject;
});
In this case if i'm going to use it inside the HTML e.g.:
<custom-input-group rident='sg'></custom-input-group>
what i get rendered:
<div>
<input ng-model="sgEnd" ng-change="sgEndChange()">
<input ng-model="sgEnd" ng-change="sgEndChange()">
<input ng-model="sgEnd" ng-change="sgEndChange()">
</div>
For the 3rd rendered input the ng-change does not working.
If set terminal:ture in the inputGroup directive i get only to "input" rendered but both of them has the same ng-model and ng-change.
So how can i make it to render something like this:
<div>
<input ng-model="sgStart" ng-change="sgStartChange()">
<input ng-model="sgEnd" ng-change="sgEndChange()">
</div>
And if u know how would u be so nice to let me know only the "how" but the "why" aswell.
Thank you in advance.

Pass json value as ng-model value in angular 1.2

I'm trying to bind 2 separate elements so that one can trigger the other. The first step in this, is adding an identifying variable to my component template.
Here's the bullet.html template:
<div class="button bullet" ng-model="component.bullet.show_on_click" ng-click="showElementByUniqueName( component.bullet.show_on_click )"><p>{{component.bullet.text}}</p></div>
I'd like to know what is the correct syntax to set ng-model as the VALUE in component.bullet.show_on_click. At the moment, in the final html, ng-model turns out just as shown in the template. I have tried single speech marks and single AND double curly braces; All throw errors.
Any help, much appreciated!
EDIT
On request, here is some more detail:
The eng-bullet attribute fires up the engBullet directive:
app.directive('engBullet', function() {
return {
restrict: 'A',
replace: true,
templateUrl: 'components/bullet.html',
link: function(scope, element, attrs) {
// following function referenced in bullet.html
scope.showElementByUniqueName = function (showOnClick) {
// remove 'replaces' element
$('#'+$('#'+showOnClick).attr('data-replaces')).addClass('hidden');
// hide all popups (in case another popup is currently visible)
$('.popup').addClass("hidden");
// show selected popup
$('#'+showOnClick).removeClass("hidden");
}
}
};
});
The eng-popup attribute fires up the engPopup directive:
app.directive('engPopup', function() {
return {
restrict: 'A',
replace: true,
templateUrl: 'components/popup.html',
link: function(scope, element, attrs) {
scope.show = true;
scope.complete = false;
// watch for this popup being made visible and check if
scope.$watch(function() { return element.is(':visible') }, function() {
scope.$parent.componentCompleted(attrs.id);
});
}
};
});
..which loads in the components/popup.html template:
<div class="hidden popup {{component.popup.type}}" id="{{component.popup.name}}" data-replaces="{{component.popup.replaces}}" eng-completable ng-show="component.popup.name">
<div ng-if="component.popup.type=='overlay'">
<div class="float-right button close-button">X</div>
</div>
<p class="heading">{{component.popup.heading}}</p>
<div class="popup-content">
<div ng-if="0" ng-repeat-start="(innerIndex, component) in component.popup.popup_components"></div>
<div ng-if="0" ng-repeat-start="(type, object) in component"></div>
<div ng-attr-id="{{'p' + pageId + '-s' + skey + '-c' + ckey + '-component-' + index + '-innerComponent-' + innerIndex}}" ng-switch="type">
<div ng-switch-when="image" eng-image></div>
<div ng-switch-when="paragraph" eng-paragraph></div>
</div>
<div ng-if="0" ng-repeat-end></div>
<div ng-if="0" ng-repeat-end></div>
</div>
</div>
I'm not sure this is really relevant to the question though, which is how do I get the VALUE in component.bullet.show_on_click to present in the final html as the value of ng-model in the bullet html template, eg:
ng-model="unique_name_here"
?
Thanks.

Use link function in directives to append different HTML elements

Fiddle
I have two buttons. When pressed it displays a modal, with som text. But I also want to add some html dynamically depending on which button is pressed.
I have tried both $observe and $watch methods, but I'm having problems making it work.
here is my code.
angular.module('TM', [])
.controller('protocolCtrl', function(){
this.text = 'Now looking at the protocol part';
this.modalId = 'protocolModal';
})
.controller('categoryCtrl', function(){
this.text = 'Now looking at the category part';
this.modalId = "categoryModal";
})
.directive('modalDirective', function(){
return {
restrict: 'E',
scope: {
ctrl: '=',
modalId: '#',
},
template: ['<div id="{{modalId}}" class="modal fade" role="dialog">',
'<div class="modal-dialog">',
'<div class="modal-content">',
'<div class="modal-header">',
'<h4 class="modal-title">Modal Header</h4>',
'</div>',
'<div class="modal-body">',
'<p> {{ ctrl.text }} </p>',
'</div>',
'<div class="modal-footer">',
'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>',
'</div>',
'</div>',
'</div>',
'</div>'].join(''),
link: function(scope, element, attrs) {
element.$observe('modalId', function(){
var modal = element.find('#{{modalId}}');
if(modal == 'protocolModal'){
element.find('#{{modalId}}').append('<div>this is a protocol test...</div>');
} else {
element.find('#{{modalId}}').append('<div>this is a category test...</div>');
}
});
}
}
});
I don't think there is element.$observe - there is attrs.$observe and scope.$watch. You already have modelId on the scope, so let's use that.
Also, instead of the wonky .find by id, inject an element as a placeholder for the template and replaceWith it accordingly:
template: '<div id="{{modalId}}">\
...\
<div class="modal-body">\
<template-placeholder></template-placeholder>\
</div>\
</div>",
link: function(scope, element){
// ...
var unwatch = scope.$watch("modalId", function(val){
var placeholder = element.find('template-placeholder');
if(val == 'protocolModal'){
placeholder.replaceWith('<div>this is a protocol test...</div>');
} else {
placeholder.replaceWith('<div>this is a category test...</div>');
}
unwatch(); // seems like you don't really need to set it again
}
}
See i updated your Fiddle
Use attr in link function. because you already given attribute to
your html i.e: modal-id="{{pctrl.modalId}}
<modal-directive ctrl="pctrl" modal-id="{{pctrl.modalId}}"></modal-directive>
if(attrs.modalId == 'protocolModal'){
element.find('#{{modalId}}').append('<div>this is a protocol test...</div>');
} else {
element.find('#{{modalId}}').append('<div>this is a category test...</div>');
}
Edit :
use $timeout
$timeout(function () {
if (attrs.modalId == 'protocolModal') {
element.find('#' + attrs.modalId).append('<div>this is a protocol test...</div>');
} else {
element.find('#' + attrs.modalId).append('<div>this is a category test...</div>');
}
}, 1000)
Now why $timeout because you are applying template and and at same
time your link function append your div so it will not apply your div
.So first apply template and then in template append your div
And if you want to show that div in popup content the use this selector.
see this example: https://jsfiddle.net/kevalbhatt18/o76hxj69/6/
element.find('#'+attrs.modalId +' .modal-body').append('<div>this is a protocol test...</div>');
If your two DOM structure diverses, you can consider using two different templates depending on some parameter value.
templateUrl can be specified as a function, such as:
angular.module('Joy', [])
.controller('ProfileCtrl', ['$scope', function ($scope) {
$scope.user = {
name: 'Elit'
};
}])
.directive('profile', [function () {
return {
restrict: 'A',
templateUrl: function (elem, attrs) {
return 'style-' + attrs.color + '.html';
}
};
}]);
And use the directive as:
<div ng-app="Joy" id="play-ground" ng-controller="ProfileCtrl">
<div profile color="red"></div>
<div profile color="green"></div>
</div>
In this case, if the color is red, the directive will load template from style-red.html. Otherwise from style-green.html.
In your case, you might maintain a flag in the outside controller. Clicking either button will change this flag value and pass in to the directive. The directive will load different templates accordingly.

Categories

Resources