How to call custom function in AngularJS Directive - angularjs

I'm trying to call $scope function in AngularJS Directive in following way
JS
var app = angular.module('app', []);
app.controller('customDirEx', ['$scope', function ($scope) {
$scope.users = [
{
name: 'ABC',
rno: '100'
},
{
name: 'DEF',
rno: '200'
}
];
$scope.onChangeFoo = function() {
console.log('test');
}
$scope.dataChange = function() {
console.log('test abc', $scope);
$scope.onInitEle();
}
$scope.dataChange();
}]);
app.directive('studentInfo', function(){
var directive = {};
directive.scope = {
user: '=user',
onInitEle: '='
};
directive.restrict = 'EA';
directive.template = '<div>Name: {{user.name}}<br>R.NO: {{user.rno}}</div>';
return directive;
});
HTML
<body ng-app="app">
<div ng-controller="customDirEx">
<student-info ng-repeat="user in users" user="user" on-init-ele="onChangeFoo"></student-info>
</div>
</body>
$scope.onInitEle is not a function - this is the error I'm getting
The purpose of calling onClickEle instead of onChangeFoo here is too reuse the JS at multiple places so that I can call onChangeBar when required.

First you have to replace "onClickEle: '='" with "onClickEle: '&'"
The use of & means you are passing reference.
The second mistake is you didn't call it from your template. So, I have changed your template code as:
directive.template = '<div ng-click="onClickEle()"> Name: {{user.name}}<br>R.NO: {{user.rno}}</div>';
The third mistake is: you are calling $scope.onClickEle(); in controller, however onClickEle() not defined in controller, its under directive. So, controller unable to find the method.
The forth mistake is you are passing on-click-ele="onChangeFoo" in the direcive, the correct syntax will be:
on-click-ele="onChangeFoo()"
The working updated code given below:
var app = angular.module('app', []);
app.controller('customDirEx', ['$scope', function ($scope) {
$scope.users = [
{
name: 'ABC',
rno: '100'
},
{
name: 'DEF',
rno: '200'
}
];
$scope.onChangeFoo = function() {
console.log('test....');
}
$scope.dataChange = function() {
console.log('test abc', $scope);
//$scope.onClickEle();
}
$scope.dataChange();
}]);
app.directive('studentInfo', function(){
var directive = {};
directive.scope = {
user: '=user',
onClickEle: '&'
};
directive.restrict = 'EA';
directive.template = '<div ng-click="onClickEle()"> Name: {{user.name}}<br>R.NO: {{user.rno}}</div>';
return directive;
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="customDirEx">
<student-info ng-repeat="user in users" user="user" on-click-ele="onChangeFoo()"></student-info>
</div>
</body>
</html>

Somehow I can manage this by creating separate controller for directive but don't know the theory behind, it would be very helpful if someone explains clearly.
JS
var app = angular.module('app', []);
app.controller('customDirEx', ['$scope', function ($scope) {
$scope.users = [
{
name: 'ABC',
rno: '100'
},
{
name: 'DEF',
rno: '200'
}
];
$scope.onChangeFoo = function() {
console.log('test');
}
}]);
app.controller('StudentCtrl', ['$scope', function($scope){
$scope.onInitEle();
}]);
app.directive('studentInfo', function(){
var directive = {};
directive.scope = {
user: '=user',
onInitEle: '='
};
directive.restrict = 'EA';
directive.template = '<div>Name: {{user.name}}<br>R.NO: {{user.rno}}</div>';
directive.controller = 'StudentCtrl';
return directive;
});
HTML
<body ng-app="app">
<div ng-controller="customDirEx">
<student-info ng-repeat="user in users" user="user" on-init-ele="onChangeFoo"></student-info>
</div>
</body>
Working JSFiddle

Related

Angular directive with ng-template

Today I'm trying to develop a popover directive. I don't know why the ng-repeat inside the styles-select directive wich is insered in the popover after click doesn't work(<- Edited it works now)... And I want to get the value of "selectedStyles" in my controller "MyController" without passing it through the directive.
var app = angular.module('MyApp', []);
app.controller('MyController', ['$scope', function($scope) {
$scope.selectedStyles = [];
$scope.$watch('selectedStyles', function(newValue, oldValue) {
console.log(newValue);
});
}]);
app.directive('popover', ['$compile', '$templateCache', function($compile, $templateCache) {
return {
restrict: 'A',
scope: {
header: '#header',
template: '=template'
},
link: function(scope, element) {
element[0].onclick = function (event) {
var popover = document.createElement('div'),
header = document.createElement('h4'),
content = document.createElement('p');
header.textContent = scope.header;
content.innerHTML = $templateCache.get(scope.template);
popover.appendChild(header);
popover.appendChild(content);
document.body.appendChild($compile(popover)(scope)[0]);
scope.$apply();
}
}
};
}]);
app.directive('stylesSelect', ['$compile', '$filter', function($compile, $filter) {
return {
restrict: 'E',
scope: {
selectedStyles: '=selectedStyles'
},
template: '<div ng-repeat="s in styles"><label><input type="checkbox" ng-model="s.selected" ng-change="selectStyle()" /> {{s.label}}</label></div>',
link: function(scope, element) {
scope.styles = [
{label: 'Hipster', selected: false},
{label: 'Hip-Hop', selected: false},
{label: 'Punk', selected: false}
];
scope.selectStyle = function() {
scope.selectedStyles = $filter('filter')(scope.styles, {selected: true});
};
}
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<div ng-app="MyApp">
<div ng-controller="MyController">
{{test}}
<button popover template="'popoverContent.html'" header="Select your styles" type="button">Show Popover</button>
<script type="text/ng-template" id="popoverContent.html">
<styles-select selected-styles="selectedStyles"></styles-select>
</script>
</div>
</div>
It gonna make me crazy... Please Help lol
Thank you
Instead of changing values in different scopes, try to use a service with a promise. This way the popover service is more reusable in your application.
var app = angular.module('MyApp', []);
app.controller('MyController', ['$scope', 'popover',
function($scope, popover) {
$scope.selectedStyles = [];
$scope.showStylesSelect = function() {
popover.show({
templateUrl: 'popoverContent.html',
scope: {
header: 'Select your style',
styles: [{
label: 'Hipster',
selected: false
}, {
label: 'Hip-Hop',
selected: false
}, {
label: 'Punk',
selected: false
}]
}
}).then(function(result) {
$scope.selectedStyles = result.selectedStyles;
});
};
$scope.$watch('selectedStyles', function(newValue, oldValue) {
console.log(newValue);
});
}
]);
app.factory('popover', ['$rootScope', '$q', '$compile', '$templateCache',
function($rootScope, $q, $compile, $templateCache) {
function showPopover(options) {
var defer = $q.defer(),
scope = $rootScope.$new(),
popover = document.createElement('div'),
header = document.createElement('h4'),
content = document.createElement('p');
angular.extend(scope, options.scope || {});
scope.close = function() {
popover.parentNode.removeChild(popover);
defer.resolve(scope);
};
header.textContent = options.header || '';
content.innerHTML = $templateCache.get(options.templateUrl);
popover.appendChild(header);
popover.appendChild(content);
document.body.appendChild($compile(popover)(scope)[0]);
return defer.promise;
}
return {
show: showPopover
}
}
]);
app.directive('stylesSelect', ['$filter',
function($filter) {
return {
restrict: 'E',
scope: false,
template: '<div ng-repeat="s in styles"><label><input type="checkbox" ng-model="s.selected" ng-change="selectStyle()" /> {{s.label}}</label></div><button ng-click="close()">close</button>',
link: function(scope) {
scope.selectStyle = function() {
scope.selectedStyles = $filter('filter')(scope.styles, {
selected: true
});
};
}
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<div ng-app="MyApp" class="ng-scope">
<script type="text/ng-template" id="popoverContent.html">
<styles-select selected-styles="selectedStyles"></styles-select>
</script>
<div ng-controller="MyController" class="ng-scope ng-binding">
<button ng-click="showStylesSelect()">Show Popover</button>
</div>
</div>

how to make custom directive?

I am new to angularjs ,building my first angular app now i want to display the data which i displayed right now in a table using a customized directive.
can anyone tell me how can i do this?
i just want to have a custom directive and all data should be displayed using that directive.
is customized directive should placed in a separate file?
please guide me how can i do it?
here is my controller:
'use strict';
app.controller('myAppCtrl', function ($scope, $http) {
$scope.names = []
$http.get('https://www.reddit.com/r/worldnews/new.json')
.success(function (response) {
$scope.names = response.data.children;
})
});
https://jsfiddle.net/rr6q0umb/4/
You should go through some resources online to study about angular directives .
https://docs.angularjs.org/guide/directive
http://www.tutorialspoint.com/angularjs/angularjs_custom_directives.htm
Simple directive approach for beginners
//Controller
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
//Directive
app.directive('simpleDemo',function(){
var newtemplate = function(){
var template = '<i class="glyphicon glyphicon-remove"><i>';
return template;
}
return {
restrict: 'E',
template: newtemplate
}
})
//html
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<button><simple-demo></simple-demo></button>
It might help you!
<html>
<head>
<title>Angular JS Custom Directives</title>
</head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var mainApp = angular.module("mainApp", []);
mainApp.directive('student', function() {
var directive = {};
directive.restrict = 'E';
directive.template = "Student: <b>{{student.name}}</b> , Roll No: <b>{{student.rollno}}</b>";
directive.scope = {
student : "=name"
}
directive.compile = function(element, attributes) {
element.css("border", "1px solid #cccccc");
var linkFunction = function($scope, element, attributes) {
element.html("Student: <b>"+$scope.student.name +"</b> , Roll No: <b>"+$scope.student.rollno+"</b><br/>");
element.css("background-color", "#ff00ff");
}
return linkFunction;
}
return directive;
});
mainApp.controller('StudentController', function($scope) {
$scope.Mahesh = {};
$scope.Mahesh.name = "Mahesh Parashar";
$scope.Mahesh.rollno = 1;
$scope.Piyush = {};
$scope.Piyush.name = "Piyush Parashar";
$scope.Piyush.rollno = 2;
});
</script>
<body>
<h2>AngularJS Sample Application</h2>
<div ng-app="mainApp" ng-controller="StudentController">
<student name="Mahesh"></student><br/>
<student name="Piyush"></student>
</div>
</body>
</html>
Reference URLs:
https://www.airpair.com/angularjs/posts/creating-components-p3-angular2-directives
http://tutorials.jenkov.com/angularjs/custom-directives.html
http://www.sitepoint.com/practical-guide-angularjs-directives/

Passing scope object to Angular Directive via $compile

I know that if I have a directive in HTML, I can pass objects from my $scope to it:
<mydirective some-data="someData"></mydirective>
...where someData might be JSON object.
Is it possible to pass a reference to someData if I create the directive dynamically and use $compile?
$scope.someData = { firstName: 'John', lastName: 'Doe' };
var link = $compile("<mydirective some-data='???'></mydirective>");
var content = link($scope);
$(body).append(content);
Yes you can pass object to
var myApp = angular.module('myApp',[]);
myApp.directive('passObject', function() {
return {
restrict: 'E',
scope: { obj: '=' },
template: '<div>Hello, {{obj.prop}}!</div>'
};
});
myApp.controller('MyCtrl', function ($scope) {
$scope.obj = { prop: "world" };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
<div ng-controller="MyCtrl">
<pass-object obj="obj"></pass-object>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('passObject', function() {
return {
restrict: 'E',
scope: { obj: '=' },
template: '<div>Hello, {{obj.prop}}!</div>'
};
});
myApp.controller('MyCtrl', function ($scope) {
$scope.obj = { prop: "world" };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<div ng-controller="MyCtrl">
<pass-object obj="obj"></pass-object>
</div>
directive

AngularJS - custom filter, model doesn't update in view

I have a custom filter set up that triggers when the user clicks on a checkbox. I use a directive to render the DOM elements, and attach a listener on the checkbox which when clicked, triggers the filter function that's exposed on the $scope.
The $scope.model which is used in the view should get overwritten by the result of the filter function, and the return object looks ok (e.g. the console.log()) but the view doesn't update. What am I doing wrong?
http://jsfiddle.net/r3pXc/1/
The view:
<body ng-app="app">
<div ng-controller="mainCtrl">
<div list-directive />
</div>
The template:
<script type="text/ng-template" id="list.html">
<input type="checkbox" class="control">
<div ng-repeat="player in model">
Name: {{player.firstName}}, Price: {{player.price}}
</div>
</script>
The module and controller:
var app = angular.module('app', []);
app.controller('mainCtrl', ['$scope', '$filter', function($scope, $filter){
$scope.model = [{ firstName: 'foo', price: 100 }, { firstName: 'bar', price: 50 }, { firstName: 'foobar', price: 0}];
$scope.filter = function() {
$scope.model = $filter('listFilter')($scope.model);
console.log($scope.model);
}
}]);
The directive:
app.directive('listDirective', function(){
return {
restrict: 'AE',
templateUrl: 'list.html',
link: function($scope, iElm, iAttrs, controller) {
iElm.bind('click', function(e){
var el = angular.element(e.target);
if (el.hasClass('control')) {
$scope.filter();
};
});
}
};
});
And the filter:
app.filter('listFilter', function(){
return function(input) {
var results = [];
angular.forEach(input, function(val, key){
if (val.price != 0) {
results.push(val);
}
});
return results;
}
});
Need to manually call the digest cycle with $apply(), because I don't listen on the elements with ng- event handlers:
$scope.filter = function() {
$scope.model = $filter('listFilter')($scope.model);
$scope.$apply();
}

Angular directive how to add an attribute to the element?

I'm wondering what's the way to do work this snippet:
//html
<div ng-app="app">
<div ng-controller="AppCtrl">
<a my-dir ng-repeat="user in users">{{user.name}}</a>
</div>
</div>
//js
var app = angular.module('app', []);
app.controller("AppCtrl", function ($scope) {
$scope.users = [{name:'John',id:1},{name:'anonymous'}];
$scope.fxn = function() {
alert('It works');
};
})
app.directive("myDir", function ($compile) {
return {
link:function(scope,el){
el.attr('ng-click','fxn()');
//$compile(el)(scope); with this the script go mad
}
};
});
I know it's about the compile phase
but I don't get the point so a short explanation would be
very appreciate.
A directive which adds another directive to the same element:
Similar answers:
How to get ng-class with $dirty working in a directive?
creating a new directive with angularjs
Here is a plunker: http://plnkr.co/edit/ziU8d826WF6SwQllHHQq?p=preview
app.directive("myDir", function($compile) {
return {
priority:1001, // compiles first
terminal:true, // prevent lower priority directives to compile after it
compile: function(el) {
el.removeAttr('my-dir'); // necessary to avoid infinite compile loop
el.attr('ng-click', 'fxn()');
var fn = $compile(el);
return function(scope){
fn(scope);
};
}
};
});
Much cleaner solution - not to use ngClick at all:
A plunker: http://plnkr.co/edit/jY10enUVm31BwvLkDIAO?p=preview
app.directive("myDir", function($parse) {
return {
compile: function(tElm,tAttrs){
var exp = $parse('fxn()');
return function (scope,elm){
elm.bind('click',function(){
exp(scope);
});
};
}
};
});
You can try this:
<div ng-app="app">
<div ng-controller="AppCtrl">
<a my-dir ng-repeat="user in users" ng-click="fxn()">{{user.name}}</a>
</div>
</div>
<script>
var app = angular.module('app', []);
function AppCtrl($scope) {
$scope.users = [{ name: 'John', id: 1 }, { name: 'anonymous' }];
$scope.fxn = function () {
alert('It works');
};
}
app.directive("myDir", function ($compile) {
return {
scope: {ngClick: '='}
};
});
</script>

Resources