How to pass a value into a directive? - angularjs

I'm using a directive to insert a youtube player in my templates,
app.directive('youtube', function($window, youTubeApiService) {
return {
restrict: "E",
scope: {
videoid: "#"
},
template: '<div></div>',
link: function(scope, element, attrs, $rootScope) {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
youTubeApiService.onReady(function() {
player = setupPlayer(scope, element);
});
function setupPlayer(scope, element) {
return new YT.Player(element.children()[0], {
playerVars: {
autoplay: 0,
html5: 1,
theme: "light",
modesbranding: 0,
color: "white",
iv_load_policy: 3,
showinfo: 1,
controls: 1
},
videoId: scope.videoid,
});
}
scope.$watch('videoid', function(newValue, oldValue) {
if (newValue == oldValue) {
return;
}
Player.cueVideoById(scope.videoid);
});
}
};
});
My html looks something like this,
<div class="container-info">
<ul class="trailers">
<li>ePbKGoIGAXY</li>
<li>KlyknsTJk0w</li>
<li>nyc6RJEEe0U</li>
<li>zSWdZVtXT7E</li>
<li>Lm8p5rlrSkY</li>
</ul>
<div class="container-trailers">
<youtube videoid="ePbKGoIGAXY"></youtube>
</div>
</div>
What I want to do is click on one of the links and then change the value of videoid so a different youtube link is rendered.
<div class="container-info">
<ul class="trailers">
<li>ePbKGoIGAXY</li>
<li>KlyknsTJk0w</li>
<li>nyc6RJEEe0U</li>
<li>zSWdZVtXT7E</li> <-- clicked element
<li>Lm8p5rlrSkY</li>
</ul>
<div class="container-trailers">
<youtube videoid="zSWdZVtXT7E"></youtube> <-- new youtube link
</div>
</div>

You can use $watch and ng-click:
JSFiddle
HTML:
<div ng-app="app">
<div class="container-info">
<ul class="trailers">
<li>ePbKGoIGAXY</li>
<li>KlyknsTJk0w</li>
</ul>
<div class="container-trailers">
<youtube videoid="videoid"></youtube>
</div>
</div>
</div>
JS:
var app = angular.module("app", []);
app.directive('youtube', function($window) {
return {
restrict: "E",
scope: {
videoid: "="
},
template: '<div></div>',
link: function(scope, element, attrs, $rootScope) {
scope.$watch('videoid', function (newVal, oldVal) {
console.log(newVal);
});
}
};
});

Related

Update child directive on click

is there a way to update a child directive on click? In my plnkr, column 1 contains a list of names. If you click on the name it will populate the info into the contact directive in column 2. If I make a change in the textbox in column 2, the data in the info directive in column 3 will also change as well. Here is my plnkr:
http://plnkr.co/edit/gcZbd9letYhA4ViBQJ0Q?p=preview
Here is my JS:
var app = angular.module('myApp', []);
app.controller('contactController', function() {
this.contacts = [
{
id: 1,
name: 'Bob'
},
{
id: 2,
name: 'Sally'
},
{
id: 3,
name: 'Joe'
}
]
this.selectedContact;
this.PublishData = function(data) {
this.selectedContact = data;
}
this.UpdateData = function(data) {
for (var i = 0; i < this.contacts.length; i++) {
if (this.contacts[i].id === data.id) {
this.contacts[i] = angular.copy(data);
}
}
}
});
app.directive('contactDirective', function () {
return {
restrict: 'E',
templateUrl: 'contact.html',
scope: {
myModel: '=',
updateData: '&'
},
link: function (scope, element, attrs) {
scope.$watch('myModel', function (newValue, oldValue) {
scope.contact = angular.copy(newValue);
});
}
}
});
app.directive('infoDirective', function () {
return {
restrict: 'E',
templateUrl: 'info.html',
scope: {
contactObject: '='
},
link: function (scope, element, attrs) {
}
}
});
you can simply use $broadcast and $on services
with $broadcat you create an event and you pass a parameter
with $on you listen that event and take that value
I edited your code in this way:
<!--Contact template-->
<div class="col-sm-6">
<b>Column 2</b>
<input type="text" ng-model="newName" />
<button ng-click="updateData({data:contact,newName:newName})">Update</button>
</div>
<div class="col-sm-6">
<b>Column 3</b>
<info-directive contact-object="contact"></info-directive>
</div>
<!-- Your Index file -->
<body ng-app="myApp">
<div ng-controller="contactController as $ctrl">
<div class="row col-md-12">
<div class="col-sm-2">
<b>Column 1</b>
<div ng-repeat="contact in $ctrl.contacts">
</div>
</div>
<div class="col-sm-6">
<contact-directive my-model="$ctrl.selectedContact" update-data="$ctrl.UpdateData(data,newName)"></contact-directive>
</div>
</div>
</div>
</body>
//and your controller
var app = angular.module('myApp', []);
app.controller('contactController', function() {
this.contacts = [
{
id: 1,
name: 'Bob'
},
{
id: 2,
name: 'Sally'
},
{
id: 3,
name: 'Joe'
}
]
this.selectedContact;
this.PublishData = function(data) {
this.selectedContact = data;
}
this.UpdateData = function(data,newName) {
for (var i = 0; i < this.contacts.length; i++) {
if (this.contacts[i].id === data.id) {
this.contacts[i].name = newName;
}
}
}
});
app.directive('contactDirective', function () {
return {
restrict: 'E',
templateUrl: 'contact.html',
scope: {
myModel: '=',
updateData: '&'
},
link: function (scope, element, attrs) {
scope.$watch('myModel', function (newValue, oldValue) {
scope.newName = newValue.name;
scope.contact = angular.copy(newValue);
});
}
}
});
app.directive('infoDirective', function () {
return {
restrict: 'E',
templateUrl: 'info.html',
scope: {
contactObject: '='
},
link: function (scope, element, attrs) {
}
}
});

Created a custom directive for tabs. On click of Next Button need to go to the next tab, and on click of back button need to come to previous tab

My Main.Html which contains the tab directives.
<div class="modal-header">
<span class="modal-title">Add Report Template</span>
<div class="closeButton right" ng-click="closeModal()"></div>
</div>
<div class="modal-body">
<tab-set>
<tab heading="1st Tab">
This is the content for 1st Tab
</tab>
<tab heading="2nd Tab">
This is the content for 2nd tab
</tab>
<tab heading="3rd Tab">
This is the content for 3rd tab.
</tab>
</tab-set>
</div>
<div class="modal-footer">
<div>
<button type="text" class="grayButton right" ng-click="goToNextTab()">Next</button>
<button type="text" class="grayButton left" ng-click="goToPreviousTab()">Back</button>
</div>
</div>
My Main.controller where i need the define the function for Next and Back Button
(function () {
'use strict';
angular
.module('myApp')
.controller('Controller', ['$scope', function($scope,) {
var vm = this;
/////////////// Function to Change tab on click of the Back/Next Button ///////////////
$scope.goToNextTab = function() {
};
$scope.goToPreviousTab = function() {
};
}]);
})();
My TabSet directive that displays the 3 tabs.
angular
.module('myApp')
.directive('TabSet', function() {
return {
restrict: 'E',
transclude: true,
scope: { },
templateUrl: 'tabset.html',
bindToController: true,
controllerAs: 'tabs',
controller: function($scope) {
var self = this;
self.tabs = [];
self.addTab = function addTab(tab) {
self.tabs.push(tab);
if(self.tabs.length === 1) {
tab.active = true;
}
};
self.select = function(selectedTab) {
angular.forEach(self.tabs, function(tab) {
if(tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
};
}
};
});
Tabset Html for the corresponding tabset directive.
<div role="tabpanel" class="tabsets">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" ng-repeat="tab in tabs.tabs" ng-class="{'active': tab.active}">
{{tab.heading}}
</li>
</ul>
<div ng-transclude></div>
</div>
This is the Tab directive for creating the individual tabs.
angular
.module('myApp')
.directive('Tab', function() {
return {
restrict: 'E',
transclude: true,
template: `<div role="tabpanel" ng-show="active"><div ng-transclude></div></div>`,
require: '^TabSet',
scope: {
heading: '#'
},
link: function(scope, elem, attr, tabs) {
scope.active = false;
tabs.addTab(scope);
}
}
});
I am not too sure what I am missing, but for the given structure I want to switch tabs based on click of the Next as well as Back Button defined in main.html.
I see your code is wrong on link function of Tab directive.
link: function(scope, elem, attr, reporttabs) {
scope.active = false;
tabs.addTab(scope);
}
You need to change tabs.addTab to reporttabs.addTab
And here is the solution for the feature you want to implement. You need to add a selectedTabIndex property into scope of Tabset. So you can use scope.$watch function and when the selectedTabIndex has changed you can call scope.select(selectedTab). Here code example:
angular
.module('myApp')
.controller('Controller', ['$scope', function($scope,) {
var vm = this; vm.selectedTabIndex = 0;
$scope.goToNextTab = function() {
vm.selectedTabIndex += 1;
};
$scope.goToPreviousTab = function() {
vm.selectedTabIndex -= 1;
};
}]);
angular
.module('myApp')
.directive('TabSet', function() {
return {
restrict: 'E',
transclude: true,
scope: { 'selectedTabIdex': '=' },
templateUrl: 'tabset.html',
bindToController: true,
controllerAs: 'tabs',
controller: function($scope) {
var self = this;
self.tabs = [];
self.addTab = function addTab(tab) {
self.tabs.push(tab);
if(self.tabs.length === 1) {
tab.active = true;
}
};
self.select = function(selectedTab) {
angular.forEach(self.tabs, function(tab) {
if(tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
};
$scope.$wacth('selectedTabIndex', function(newValue, oldValue) {
var index = newValue;
if(index >= self.tabs.length) {
return $scope.selectedTabIndex = 0;
}
if(index < 0) {
return $scope.selectedTabIndex = self.tabs.length - 1;
}
self.select(self.tabs[index]);
});
}
};
});

AngularJs ng-transclude orphan issue

Ive gotten a problem with ng-transcule orphan issue, wich directed me to this link:
https://docs.angularjs.org/error/ngTransclude/orphan?p0=%3Cng-transclude%3E
This happened when trying to implement a tab directive I saw on thinkster.io, into the code of the shaping up with Angularjs course of codeschool.
I've must have donse something wrong but can't figure out what exactly.
I implemented it creating a new module called tab and making it a dependency on the product-store module, this is part of the code:
index.html:
<body ng-controller="StoreController as store">
<h1 ng-bind="'Welcome' | capitalize"></h1>
<ul class="list-group">
<li class="list-group-item" ng-repeat="product in store.products | filter: store.search | orderBy: '-price'" ng-hide="product.soldOut">
<h3>
<product-title product="product"></product-title>
</h3>
<product-panels product="product"></product-panels>
</li>
</ul>
</body>
</html>
codeschoolapp.js:
(function(){
angular.element(document).ready(function() {
angular.bootstrap(angular.element("body")[0], ['store'], {
strictDi: true
});
});
var store = angular.module('store', ['store-products']);
store.controller('StoreController', ['$http', function($http){
var vm = this;
vm.products = [];
$http.get('json/products.json').success(function(data){
vm.products = data;
});
}]);
store.filter('capitalize', function(){
return function (text) {
return text.toUpperCase();
};
});
})();
product.js:
(function(){
var store = angular.module('store-products', ['tab']);
store.directive("productPanels", function(){
return {
restrict: 'E',
templateUrl: "product-panels.html",
scope: { "product" : "=" }
};
});
store.directive("productDescription", function(){
return {
restrict: 'E',
scope: { "product" : "=" },
templateUrl: "product-description.html"
};
});
store.directive("productSpecs", function(){
return {
restrict: 'E',
scope: { "product" : "=" },
templateUrl: "product-specs.html"
};
});
store.directive("productReviews", function(){
return {
restrict: 'E',
scope: { "product" : "=" },
templateUrl: "product-reviews.html"
};
});
store.directive("productTitle", function(){
return {
restrict: 'E',
scope: { "product" : "=" },
templateUrl: "product-title.html"
};
});
})();
tab.js:
(function(){
var tab = angular.module('tab', []);
tab.directive('tab', function(){
return {
restrict: 'E',
transclude: true,
templateUrl: 'tab.html',
require: '^tabset',
scope: {
heading: '#'
},
link: function(scope, elem, attr, tabsetCtrl) {
scope.active = false;
tabsetCtrl.addTab(scope);
}
};
});
tab.directive('tabset', function() {
return {
restrict : 'E',
tranclude : true,
scope: {
type: '#'
},
templateUrl: 'tabset.html',
bindToController: true,
controllerAs: 'tabset',
controller: function() {
var self = this;
self.tabs = [];
self.classes = {};
if(self.type === 'pills') {
self.classes['nav-pills'] = true;
}
else {
self.classes['nav-tabs'] = true;
}
self.addTab = function (tab){
self.tabs.push(tab);
if(self.tabs.length === 1) {
tab.active = true;
}
};
self.select = function(selectedTab) {
angular.forEach(self.tabs, function(tab) {
if(tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
};
}
};
});
})();
relevant templates:
tabset.html:
<div role="tabpanel">
<ul class="nav" ng-class="tabset.classes" role="tablist">
<li role="presentation"
ng-repeat="tab in tabsett.tabs"
ng-class="{'active': tab.active}">
<a href=""
role="tab"
ng-click="tabsett.select(tab)">{{tab.heading}}</a>
</li>
</ul>
<ng-transclude>
</ng-transclude>
</div>
tab.html:
<div role="tabpanel" ng-show="active" ng-transclude></div>
product-panels.html:
<tabset type="pills">
<tab heading="Description">
<product-description product="product"></product-description>
</tab>
<tab heading="Specifications">
<product-specs product="product"></product-specs>
</tab>
<tab heading="Reviews">
<product-reviews product="product"></product-reviews>
</tab>
</tabset>
Also here is a plunker with everything
The error's link says that I must be missing a transclude : true, but the DDOs do have that, and haven't been able to find much on the issue.
Thanks for the help
There is just a minor spelling error in tab.js : tranclude : true, should be transclude : true,

angular directive for isotope layout

I am new to angular, started exploring the custom directives, I was trying to create a custom directive for applying isotope layout once the ng-repeat completes the loading
here is following code snippet
var app = angular.module('myApp', []);
app.directive('myDirective', function($timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
if (scope.$last === true) {
$timeout(function() {
scope.$emit(
$('.grid2').isotope({
layoutMode: 'masonry',
animationOptions: {
duration: 750,
easing: 'linear',
queue: false,
}
})
);
});
}
}
}
});
app.controller('userNames', function($scope, $http) {
$http.get("apicall").success(function(response) {
$scope.names = response.response;
});
});
<div ng-controller="userNames">
<div class="grid2" my-directive ng-repeat="x in names">
<div class="box"><span>{{ x.username }}</span>
</div>
</div>
</div>
the code is not working please help in fixing this.

angularJS: watch async data in directive

I'm trying to watch a async data in my directive, here is my JS code:
(function(angular) {
var myApp = angular.module('testTree', []);
myApp.config(function($httpProvider) {
$httpProvider.defaults.headers.get = {};
$httpProvider.defaults.headers.get["Content-Type"] = "application/json";
});
myApp.factory('DataService', function($http) {
return { getData: function(prmParentId, prmParentSrc) {
var data = $.param({ 'parentId': prmParentId, 'parentSrc': prmParentSrc });
return $http.get("Temp.aspx/GetData", { params: { parentId: prmParentId, parentSrc: prmParentSrc }, data: '' }).
success(function(result) {
return result.d;
});
}
}
});
myApp.controller('myController', myController);
function myController($scope, DataService) {
$scope.treeNodes = [];
$scope.init = function() {
DataService.getData(0, 0).then(function(promise) {
$scope.treeNodes = promise.data.d;
});
}
$scope.focusNode = function() {
console.log("kuku2");
}
}
myApp.directive('nodes', function() {
return {
restrict: "E",
replace: true,
scope: {
nodes: '=',
clickFn: '&'
},
template: "<ul><node ng-repeat='node in nodes' node='node' click-fn='clickFn()'></node></ul>",
link: function(scope, element, attrs) {
scope.$watch('treeNodes', function(newVal, oldVal) {
console.log(scope.treeNodes);
}, true);
}
}
});
myApp.directive('node', function($compile) {
return {
restrict: "E",
replace: true,
scope: {
node: '=',
clickFn: '&'
},
template: "<li><span ng-click='clickFn()(node)'>{{node.ObjectName}}</span></li>",
link: function(scope, element, attrs) {
if (angular.isArray(scope.node.Children)) {
element.append("<nodes nodes='node.Children' click-fn='clickFn()'></nodes>");
$compile('<nodes nodes="node.Children" click-fn="clickFn()"></nodes>')(scope, function(cloned, scope) {
element.append(cloned);
});
}
}
}
});
})(angular);
And this is my HTML:
<div ng-app="testTree">
<div ng-controller="myController">
<div ng-init="init()">
<nodes node="treeNodes" click-fn="focusNode"></nodes>
</div>
</div>
</div>
The console in the directive's watch is always "undefined". What am I doing wrong here?
thanks.
Pass treeNodes as nodes in your directive. So you need to watch nodes.
scope.$watch('nodes', function(newVal, oldVal) {
console.log($scope.nodes);
}, true);
<div ng-app="testTree">
<div ng-controller="myController">
<div ng-init="init()">
<nodes nodes="treeNodes" click-fn="focusNode"></nodes>
</div>
</div>
</div>

Resources