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
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) {
}
}
});
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]);
});
}
};
});
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,
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.
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>