Directive that returns template needs scope variable - angularjs

The template that loads content("html/script template") for each cell:
<td class="tableColumnsDocs" ng-repeat="attobj in columns track by $index" >
<div ng-init="values = dbo.get4(attobj.key); key = attobj.key; template = attobj.template || getAttributeTemplate(dbo.clazz + attobj.key);">
<div plain-template="template">
</div>
</div>
</td>
I need the directive to access the value "template" from its directive "plain-template"
Directive:
app.directive('plainTemplate', function($parse) {
return {
templateUrl: 'testTemplate',
function (scope, element, attrs) {
console.log($parse(attrs.plainTemplate));
}
};
});

You can use something like
app.directive('plainTemplate', function($parse) {
return {
templateUrl: 'testTemplate',
scope: {
plainTemplate:"="
},
link: function (scope, element, attrs) {
console.log(scope.plainTemplate));
}
};
});
and when you call it in html your variable should be like
<plain-template test-template="anything"> </plain-template>
this is isolated scope. You can see more at https://docs.angularjs.org/guide/directive

Related

How to bind to event.time variable in parent scope from a directive with isolate scope without using $parent in directive?

angular.module('hfp.calendar')
.controller('printPreviewCntrl', ['$scope', 'htmlFromServer',
function($scope, htmlFromServer){
$scope.htmlReceived = htmlFromServer;
$scope.event = {};
}])
.directive('compile', function($compile, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$timeout(function() {
element.html(scope.$eval(attrs.compile));
$compile(element.contents())(scope);
});
}
};
})
.directive('initModel', function($compile) {
return {
restrict: 'A',
scope: {
eventField: '=initModel'
},
link: function(scope, element, attrs) {
scope.eventField = element[0].innerText;
element.attr('ng-bind', '$parent.' + attrs.initModel); // why do i have to use $parent here to make it work ?
element.removeAttr('init-model');
$compile(element)(scope);
}
};
});
<!-- clientside html -->
<input type="text" ng-model="event.time">
<div compile="htmlReceived">
</div>
<!-- html coming from server -->
<div init-model="event.time">
10:30 AM
</div>
I want to bind to the parent scope var event.time from initModel directive but it only works when i use $parent to refer to the var in parent scope. Can i achieve this binding without using $parent ?
There is no need to implement that directive with isolate scope. Simply use the $parse service:
angular.module("app",[])
.directive('initModel', function($parse) {
return {
restrict: 'A',
//scope: {
// eventField: '=initModel'
//},
link: function(scope, elem, attrs) {
var setter = $parse(attrs.initModel).assign;
setter(scope, elem.text().trim());
scope.$watch(attrs.initModel, function(value) {
elem.text(value);
});
}
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-init="event={}">
<input type="text" ng-model="event.time">
<div init-model="event.time">
10:30 AM
</div>
</body>
For more information, see AngularJS $parse Service API Reference.

Passing data from ng-click within directive into a function in the controller

I found this question which gets me almost to where I need to be.
Why doesn't ng-click work in my directive and how do I add a toggle class?
Which makes it so my ng-click within my directive template triggers a function in my controller.
http://plnkr.co/edit/GorcZZppa8qcIKbQAg2v?p=preview
The issue is that the parameter returned to my controller (item) is undefined. I need this to actually pass data from a variable within my directive to be used in the function that I will run in the controller.
Directive template file
<div class="tsProductAttribute"
ng-class="{'tsProductAttribute--selected': selected}"
ng-click="toggleState(item)">
<span class="tsProductAttribute-image">
<img ng-src="{{variantImage}}">
</span>
<span class="tsProductAttribute-desc">{{item.productName}}</span>
<select ng-model="variantImage">
<option ng-repeat="variant in item.variants" value="{{variant.image}}">{{variant.name}} - {{variant.listprice.amount}}</option>
</select>
<span class="tsProductAttribute-price">{{item.variants[0].listprice.amount}} {{item.variants[0].listprice.entity}}</span>
</div>
Directive
angular.module('msfApp')
.directive('listitem', function () {
return {
templateUrl: 'assets/templates/directives/listitem.html',
restrict: 'E',
scope: {
'item': '=',
'itemClick': '&'
},
link: function(scope, iElement, iAttrs) {
scope.selected = false;
scope.toggleState = function(item) {
scope.selected = !scope.selected;
scope.itemClick(item);
}
}
}
});
Directive implementation
<listitem item="item" item-click="toggleInBasket(item)"></listitem>
Function in controller
$scope.toggleInBasket = function(item) {
$scope.basket.toggle(item);
console.log(basket.get());
}
(item) is undefined
While passing function to directive isolated scope, you should be using &(expression binding) to pass method reference. On item-click you should mentioned actual call to controller method like toggleInBasket(item)
Markup
<listitem item="item" item-click="toggleInBasket(item)"></listitem>
And then while calling method from directive you should call it as scope.itemClick({item: item})
Directive
angular.module('msfApp').directive('listitem', function () {
return {
templateUrl: 'listitem.html',
restrict: 'E',
scope: {
'item': '=',
'itemClick': '&' // & changed to expression binding
},
link: function(scope, iElement, iAttrs) {
scope.selected = false;
scope.toggleState = function(item) {
scope.selected = !scope.selected;
scope.itemClick({item: item}); //changed call to pass item value
}
}
}
});
Demo here

ng-model with isolated scope directive

I have an isolated directive as an element
How can I bind the ngmodel of it since the return html is being overrided ?
<div ng-repeat="x in list">
<form-element ng-model="value[x.name]"></form-element>
</div>
I am having troubles adding the ngmodel to it
JS :
app.directive('formElement', function($compile) {
return {
restrict: 'E',
scope : {
type : '='
} ,
link : function(scope, element, attrs) {
scope.$watch(function () {
return scope.type ;
}, function() {
var templates = {};
templates['text'] = '<input type ="text" name="{{name}}">' ;
templates['radio'] = '<input ng-repeat="option in optionsList" name="{{name}}" type="radio">';
if (templates[inputType]) {
scope.optionsList = scope.type.data;
scope.name = scope.type.name;
element.html(templates[scope.type.inputType]);
} else {
element.html("");
}
$compile(element.contents())(scope);
}
);
}
}
});
Thanks in advance
As you want the ng-model to introduced inside the field created by the directive you could inject that ngModel inside isolated scope.
Markup
<div ng-repeat="x in list">
<form-element ng-model="x.value" type="x.inputType"></form-element>
</div>
Directive
app.directive('formElement', function($compile) {
return {
restrict: 'E',
scope: {
type: '=',
ngModel: '='
},
link: function(scope, element, attrs) {
var templates = {};
templates['text'] = '<input type ="text" name="{{name}}" ng-model="ngModel">';
templates['radio'] = '<input ng-repeat="option in optionsList" name="{{name}}" type="radio">';
if (templates[scope.type]) {
scope.optionsList = scope.type.data;
scope.name = scope.type.name;
element.append($compile(templates[scope.type])(scope));
} else {
element.html("");
}
//$compile(element.contents())(scope);
}
}
});
Demo Plunkr
What you are doing is to call a property of your isolated scope "ngModel", but you are not using the ngModelController. This doesn't mean that you are using the ngModel directive provided by Angular.
You can change the name of your ngModel property in any other name on your directive, and it should works fine.
Using ngModel it means that you add the require:'ngModel'" prop. in your directive object.
return {
restrict: 'E',
require:'ngModel',
scope: {
type: '='
}
and in the link function use the ngModelController to access to the $viewValue
function(scope, element, attrs, ngModelCtr)
{
var mymodel=ngModelCtr.$viewValue;
}
Here more info.
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

Access parent data model in directive

I wrote a directive to check for double values in a data column:
The markup
<table>
<tr data-ng-repeat-start="rowItem in vm.model.data" ...>
<td>
<input type="text" data-ng-model="rowItem.ID" data-unique-column="vm.model.data" />
</td>
...
</tr>
</table>
and the directive
(function () {
'use strict';
angular.module('app').directive('uniqueColumn', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
element.on('keyup blur', function () {
scope.$eval(attrs.uniqueColumn).forEach(function (item) {
// validation logic
});
});
}
};
});
})();
Everything works fine but I asked myself if there was a solution to access the data of my repeater, i.e. vm.model.data, without passing an argument to the directive?
Because you didn't isolate the scope, you can read javascript's prototypal inheritance. You can perhaps access a method from the child that will then lookup to the parent's. And perhaps use the $index as the parameter.
Why not use another directive to define the unique-column's model and add it as a dependency on the unique-column directive, like this:
unique-column-model directive:
app.directive('uniqueColumnModel', function() {
return {
restrict: 'A',
controller: function($scope) {
// add more logic here if necessary
},
link: function (scope, element, attrs, ngModel) {
// save the value of the uniqueColumnModel as a private var in the scope
scope.$uniqueColumnModel = scope.$eval(attrs.uniqueColumnModel);
}
};
});
unique-column directive:
app.directive('uniqueColumn', function() {
return {
restrict: 'A',
// set the uniqueColumnModel directive as a dependency (^ is to search on parents)
require: ['ngModel', '^uniqueColumnModel'],
link: function (scope, element, attrs, ngModel) {
element.on('keyup blur', function () {
// use the private $uniqueColumnModel var that was
// previously saved on the scope
angular.forEach(scope.$uniqueColumnModel, function(item) {
// validation logic
});
});
}
};
});
And on the HTML:
<tr ng-repeat="item in model.items" unique-column-model="model.items">
<td>
<input type="text" ng-model="item.id" unique-column />
</td>
</tr>
Check this plunker.
There's still room for improvement but the idea is there...

ngIf (.) DOT notation scope inheritance doesn't work 2-ways in directive template

I couldn't get why this doesn't work. I thought dot-notation on ng-if makes the 2 way data binding but I could not change the parent $scope.modal.active within ng-if scope.
template/lupus/modal/modal.html:
<div class="lupus-modal">
<img ng-src="{{lupusModalImg}}" class="img-responsive"/>
<div ng-if="modal.active" class="backdrop modal-backdrop" ng-click="modal.active = false" > //this ng-click doesn't work as I expected
<img ng-src="{{lupusModalImg}}"/>
</div>
</div>
lupusModal directive:
.directive('lupusModal', [
function () {
return {
scope: {
lupusModalImg: '='
},
restrict: 'AE',
transclude: true,
templateUrl: 'template/lupus/modal/modal.html',
controller: function ($scope, $element, $attrs, $transclude) {
$scope.modal = {
active: false,
close: function () {
$scope.modal.active = false;
$scope.$apply();
}
};
$element.on('click', function () {
$scope.modal.active = true;
$scope.$apply();
});
},
link: function (scope, iElement, iAttrs, backdropCtrl) {
//backdropCtrl.$element.$scope.slideElm[0].getBoundingClientRect();
}
};
}
]);
index.html:
If i understand the question correctly, you are creating isolated scope in your directive, which does not inherit from its parent scope.
To use the modal.active set a two way binding using = in scope declaration in directive
scope: {
lupusModalImg: '=',
modal:'='
},
and declare your directive using
<a href="javascript:void(0);" lupus-modal lupus-modal img="'img/certificates/UygunlukSertifikasi1.jpg'" modal='modal'></a>

Resources