I have this directive:
App.directive('typeahead', function($timeout) {
return {
restrict: 'AEC',
scope: {
items: '=',
prompt:'#',
title: '#',
subtitle:'#',
model: '=',
selindex: '=',
onSelect:'&'
},
link:function(scope,elem,attrs){
scope.handleSelection=function(selectedItem){
scope.model=selectedItem;
scope.current=0;
scope.selected=true;
$timeout(function(){
scope.onSelect();
},200);
};
scope.current=0;
scope.selected=true;
scope.isCurrent=function(index){
return scope.current==index;
};
scope.setCurrent=function(index){
scope.current=index;
};
},
templateUrl: 'templates/templateurl.html'
}
});
I have this html:
<typeahead items="items" prompt="Start typing a US state" title="name" subtitle="id" model="name" on-select="onItemSelected()"/>
Directice is using this template:
<input type="text" ng-model="model" placeholder="{{prompt}}" ng-keydown="selected=false"/><br/>
<div class="items" ng-hide="!model.length || selected">
<div class="item" ng-repeat="item in items | filter:model track by $index" ng-click="handleSelection(item[subtitle])" style="cursor:pointer" ng-class="{active:isCurrent($index)}" ng-mouseenter="setCurrent($index)">
<p class="title">{{item[title]}}</p>
<p class="subtitle">{{item[subtitle]}}</p>
</div>
This calls the function in the directive:
scope.handleSelection=function(selectedSubtitle){
What I try to achieve is to call:
handleSelection(item[title], item[subtitle])
And pick it up in the directive like this:
scope.handleSelection=function(selectedTitle, selectedSubtitle){
However, the selectedSubtitle in the directive remains empty. How can I pass the additional parameter to the directive?
Related
I am new to AngularJS, Somehow while going through many sites now I am able to create a directive for showing some data.Now I need to send some data to controller by clicking the button. I need to know the proper way of doing this
I have created the plunk
html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="jquery#*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="movieDesc">
<div ng-repeat="m in movies" movies="m"></div>
</body>
</html>
Directive and Controller
// Code goes here
angular.module('app', []);
angular.module('app').controller('movieDesc', function($scope) {
$scope.movies = [{
name: 'abc',
desc: 'this is desc text for the movie',
pic: 'http://png.clipart.me/graphics/thumbs/134/abstract-geometric-background-triangle-and-square-black_134053397.jpg'
}, {
name: 'def',
desc: 'this is desc text for the movie def',
pic: 'http://png.clipart.me/graphics/thumbs/201/abstract-modern-banner-background-of-geometric-shapes-abstract-geometric-form_201768245.jpg'
}, {
name: 'ghi',
desc: 'this is desc text for the movie ghi',
pic: 'http://www.cianellistudios.com/images/abstract-art/abstract-art-infinite-150.jpg'
}]
$scope.saveData = function(data) {
console.log(data);
}
});
angular.module('app').directive('movies', function() {
return {
templateUrl: "movieCard.html",
restrict: "EA",
scope: {
movies: '='
},
link: function(scope, element, attrs) {
element.addClass('moviesBox');
var clickedFn = function() {
alert("clicked");
};
console.log("console", element[0].querySelector('.btnSelect'));
var $this = element[0].querySelector('.btnSelect');
$($this).click(function() {
alert(scope.movies.desc)
})
}
}
})
My Template
<div>
<div>
<b>Name:</b> {{movies.name}}
</div>
<div>
<b>Description:</b> {{movies.desc}}
</div>
<div>
<img src="{{movies.pic}}" />
</div>
<div>
<input type="text" ng-model="movies.someText">
</div>
<div>
<input class="btnSelect" type="button" value="Desc" ng-click="clickedFn()">
</div>
<div>
<input class="btnSelect" type="button" value="Save Data" ng-click="saveData({{movies}})">
</div>
</div>
I need to send the data to the controller's $scope.saveData() function, the data will be entered through the textbox. I have given it as ng-model="movies.someText" which I suppose is the wrong way.
So please help me.
Use the & scope binding.
scope: {
movies: '=',
save: '&'
},
and in the directive template
<input type="button" ng-click="save({movie: movies})" ...>
You then bind the controller method via
<div ng-repeat="m in movies" movies="m" save="saveData(movie)"></div>
Note the argument name passed to the controller function matches the object key in the directive template.
https://plnkr.co/edit/9bF5FDea6wLn7vcGvEzU?p=preview
While you're there, use ng-src instead of src to avoid a 404 request for a non-existent image
<img ng-src="{{movies.pic}}" />
html
<body ng-controller="movieDesc">
<div ng-repeat="m in movies" movies="m">
<movies-dir
movies="m" save-data="saveData(movie)"></movies-dir>
</div>
</body>
Directive and Controller
angular.module('app', []);
angular.module('app')
.controller('movieDesc', function($scope) {
$scope.movies = [/* movie object array data */]
$scope.saveData = function(movie) {
console.log(movie);
}
});
angular.module('app').directive('moviesDir', function() {
return {
templateUrl: "movieCard.html",
restrict: "EA",
scope: {
movies: '=',
saveData: '&'
},
link: function(scope, element, attrs) {
}
}
})
Template
<div>
<input class="btnSelect" type="button" value="Save Data" ng-click="saveData({ 'movie': movies })">
</div>
You need to pass saveData as a parameter like this:
<body ng-controller="movieDesc">
<div ng-repeat="m in movies" movies="m" save-data="saveData()"></div>
And you get back in your directive like this:
return {
templateUrl: "movieCard.html",
restrict: "EA",
scope: {
movies: '=',
saveData:'='
},
link: ...
And then in your template.html, you don't need to use '{{}}' :
<input class="btnSelect" type="button" value="Save Data" ng-click="saveData(movies)">
I have a sidebar directive in my web application with a set of values that bind to some model in another controller. When page loads, all the values are fetched and populated correctly. However when the model is updated from the controller, the event is not captured by the watch setup in directive.
Here is my sidebar html:
<div class="navbar-default sidebar" ng-controller="SettingsCtrl" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav in" id="side-menu" style="padding-left: 8px;">
<li ng-repeat="profile in profiles">
<label>
<input type="radio" ng-model="profile" name="name" value="{{profile.text}}"/>
{{profile.text}}
</label>
</li>
</ul>
</div>
</div>
Directive sidebar.js:
angular.module('webApp')
.directive('sidebar',['$location',function(Request) {
return {
templateUrl:'scripts/directives/sidebar/sidebar.html',
restrict: 'E',
replace: true,
scope: false,
link: function(scope, element, attrs){
scope.$watch('profiles', function(newValue, oldValue){
console.log(newValue + ' ' + oldValue);
}, true);
}
}
}]);
Here is my SettingsCrl controller:
angular.module('webApp')
.controller('SettingsCtrl', function($scope) {
$scope.profiles = [{text: "john"}, {text: "paul"}];
function someEvent(){
$scope.profiles.push({text: "hannah"});
}
});
I have tried to do watchCollection instead, but still no luck..
Plunker Demo
I created two custom directives for template usage in a ng-repeater.
Outside of the ng-repeater, the directives work. Once I try to dynamically load the directives in a ng-repeater, the directives do not load at all. In fact - when use "Inspect Element" - the {{expressions}} do not dynamically update.
Here is how my ng-repeater looks:
<div ng-repeat="section in content">
<section class="section-{{ section.block }}" block="{{ section.block }}">{{ section.block }}</section>
</div>
I am calling the directives via restrict: C
Here is one of the directives:
.directive('sectionHeader', function() {
return {
restrict: 'EAC',
scope: {
block: '='
},
templateUrl: 'sectionHeader.html'
};
})
Here is the templateURL:
<div class="container">
<figure class="icon">
<img class="img-fluid" ng-src="{{ block.icon }}" title="App Icon">
</figure>
<h1>{{ block.title }}</h1>
<figure class="hero">
<img class="img-fluid" ng-src="{{ block.image }}" title="App">
</figure>
</div>
And a snippet of the JSON:
$scope.content = [
{
block: 'header',
icon: 'http://www.placehold.it/128x128?text=PLACEHOLpng',
title: 'Header Title',
image: 'http://www.placehold.it/1200x675?text=PLACEHOLDER'
},...
];
Now, I believe The templateUrls are not loading because it seems like the directives are being executed before ng-repeat get its content. What I believe I need to do is to execute the directives after ng-repeat receives the content. I am not sure where to start.
Thanks.
You can achieve that using $compile function.
See example on plunker.
Create general directive with $compile.
.directive('section', function($compile) {
return {
restrict: 'EAC',
scope: {
block: '='
},
link:function(scope,elem){
if(scope.block)
$compile(elem.html('<section-'+scope.block.block+' block="block">'))(scope);
}
};
})
Create two different directive.
.directive('sectionHeader', function() {
return {
restrict: 'EAC',
scope: true,
templateUrl: 'sectionHeader.html'
};
})
.directive('sectionHundred', function() {
return {
restrict: 'EAC',
scope: true,
templateUrl: 'sectionHundred.html'
};
});
And usage
<div ng-repeat="section in content">
<section block="section"></section>
</div>
JSON data:
[
{
block: 'header',
icon: 'http://www.placehold.it/128x128?text=PLACEHOLpng',
title: 'Header Title',
image: 'http://www.placehold.it/1200x675?text=PLACEHOLDER'
},
{
block: 'hundred',
icon: 'http://www.placehold.it/128x128?text=PLACEHOLpg',
title: 'Hundred Title',
content: 'Hundred Content',
link: {
copy: 'Link Copy',
title: 'Link Title',
url: '#'
},
image: 'http://www.placehold.it/1200x675?text=PLACEHOLDER'
}
];
You cannot use directive by passing their name dynamically.
But a possible workaround is to use ng-switch instead :
<div ng-repeat="section in content">
<div ng-switch="section.block">
<section ng-switch-when="header" class="section-header" block="{{ section.block }}">{{ section.block }}</section>
... another ng-switch...
</div>
See this post for more details
Though #stepan-kasyanenko gave me a correct answer - I further removed extra lines of code not needed to minimize the build.
New Plunker Link with answer added.
home.html
Old:
<div ng-repeat="section in content">
<section block="section"></section>
</div>
New:
<section ng-repeat="section in content" block="section"></section>
I placed the ng-repeat in the <section> that calls the directive
directives
.directive('sectionHeader', function() {
return {
restrict: 'EAC',
replace: true,
scope: true,
templateUrl: 'sectionHeader.html'
};
});
I added replace: true, to both directives because the ng-repeat builds out another <section> inside of the <section ng-repeat> element
Thank you #stepan-kasyanenko
Error: https://docs.angularjs.org/error/ng/areq?p0=ProjectsController&p1=not%20a%20function,%20got%20undefined
I mimicked a ng-repeat that I did earlier, the only difference being I didn't split up the directive, controller, and initializing the app into 3 different javascript files. Also, are you allowed to add multiple ng-apps to the <body> tag? If no, then that may be my problem.
HTML:
<div class="projects">
<h2>Projects</h2>
<div class="row">
<div class="col-lg-12">
<div class="row" ng-controller="ProjectsController">
<div class="project-boxes" ng-repeat="project in projects">
<project-info info="project"></project-info>
</div>
</div>
</div>
</div>
</div>
app.js:
var projectApp = angular.module("projectApp", ['ngAnimate'])
.controller('ProjectsController', ['$scope', function($scope) {
$scope.projects = [
{
link: '#',
img: 'img/box.jpeg',
description: 'Project 1'
}];
}])
.directive('projectsInfo', function() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'components/projects/projects-template/projectsInfo.html'
};
});
I had strucked in passing value from controller to directive
I have two arrays in my controller
$scope.displayPeople.push(data.userName);
$scope.displayOrg.push(data.orgname);
i need to pass these data from controller to directive
my directive
<div>
<div class="multitext-wrap blue-border">
<ul inputfocus>
<!--<li class="tag" ng-repeat="list in selecteditemsdisplay track by $index" ng-class="{selected: $index==selectedIndex}" >-->
<!--<span class="tag-label">{{list}}</span><span class="tag-cross pointer" ng-click="Delete($index,selecteditemslist[$index],list,searchid)">x</span>-->
<!--</li>-->
<li class="tag" ng-repeat="list in displayItems track by $index" ng-class="{selected: $index==selectedIndex}" >
<span class="tag-label">{{list}}</span><span class="tag-cross pointer" ng-click="Delete($index,selecteditemslist[$index],list,searchid)">x</span>
</li>
<li class="">
<input type="text" ng-model="searchModel" ng-keydown="selected=false" ng-keyup="searchItem(searchModel,searchobj)"/>
</li>
</ul>
</div>
<div class="typeahead" ng-hide="!searchModel.length || selected">
<div class="typeahead" ng-repeat="item in searchData | filter:searchModel | limitTo:8" ng-click="handleSelection(item,searchobj,$index,searchid)" style="cursor:pointer" ng-class="{active:isCurrent($index)}" ng-mouseenter="setCurrent($index)">
<div class="bs-example">
<div class="list-group list-group-item active">
{{item.displayConfig[0].propertyValue}} {{item.displayConfig[1].propertyValue}}
</div>
</div>
</div>
</div>
</div>
I was using $emit to send
in controller
$rootScope.$emit("displayEvent", {displayItems: $scope.displayPeople});
$rootScope.$emit("displayEvent", {displayItems: $scope.displayOrg});
in directive
$rootScope.$on('displayEvent', function (event, args) {
$scope.displayOrgs = args.displayItems;
console.clear();
console.info($scope.displayOrgs);
});
by doing this i getting duplicates in place of org (both people and org wher coming )
how can i solve this problem please hepl me thanks in advance
By declaring 'scope: false' you´re able to access the controller´s scope in your directive. 'false' means 'do not create an isolated scope, inherit the controllers'.
.directive('myDirective', function() {
return {
scope: false,
link: function($scope){
//Do stuff with $scope.displayOrgs
//Do stuff with $scope.displayPeople
}
};
});
This option will create an isolated scope and inherits the selected variables. This is a cleaner way of doing it.
.directive('myDirective', function() {
return {
scope:{
displayPeople:'=',
displayOrg :'=',
},
link: function($scope){
//Do stuff with $scope.displayOrgs
//Do stuff with $scope.displayPeople
}
};
});
using $emit for communication between controller and directive is not a preferable.
you need to use "=" scope of directive to allow two-way communication between controller and directive like:
directive
angular.module('YourModuleName').directive('yourDirectiveName',function () {
return{
restrict:'E',
scope:{
displayPeople:'=',
displayOrg :'=',
},
link: function postLink(scope, element, attrs) {
}
}
});
template respective to controller
<yourDirectiveName displayPeople="displayPeople" displayOrg ="displayOrg "></yourDirectiveName >