question regarding constants within angularjs. I have the following constants created within app.js:
... angular
.module('blocTime', ['firebase', 'ui.router'])
.config(config)
.constant('STOP_WATCH', {
"workTime": 1500,
"breakTime": 300
});
})();
I've injected the constant inside my directive as follows:
(function() {
function clockTimer($interval, $window, STOP_WATCH) {
return {
templateUrl: '/templates/directives/clock_timer.html',
replace: true,
restrict: 'E',
scope: {},
link: function(scope, element, attributes) {
console.log(STOP_WATCH.workTime); ...
...
angular
.module('blocTime')
.directive('clockTimer', clockTimer);
I can console log the constant from my directive just fine. However, my view is not rendering the constant. HTML:
<div>
<div class="stop-watch">{{ STOP_WATCH.workTime }}</div>
It comes back as undefined. Thoughts as to why or how to make it display in the view? Thanks
Figured it out. Within my directive I had to add scope.STOP_WATCH = STOP_WATCH:
(function() {
function clockTimer($interval, $window, STOP_WATCH) {
return {
templateUrl: '/templates/directives/clock_timer.html',
replace: true,
restrict: 'E',
scope: {},
link: function(scope, element, attributes) {
scope.STOP_WATCH = STOP_WATCH;
...
Related
I am trying to figure out how to pass a transclusion down through nested directives and bind to data in the inner-most directive. Think of it like a list type control where you bind it to a list of data and the transclusion is the template you want to use to display the data. Here's a basic example bound to just a single value (here's a plunk for it).
html
<body ng-app="myApp" ng-controller="AppCtrl as app">
<outer model="app.data"><div>{{ source.name }}</div></outer>
</body>
javascript
angular.module('myApp', [])
.controller('AppCtrl', [function() {
var ctrl = this;
ctrl.data = { name: "Han Solo" };
ctrl.welcomeMessage = 'Welcome to Angular';
}])
.directive('outer', function(){
return {
restrict: 'E',
transclude: true,
scope: {
model: '='
},
template: '<div class="outer"><inner my-data="model"><div ng-transclude></div></div></div>'
};
})
.directive('inner', function(){
return {
restrict: 'E',
transclude: true,
scope: {
source: '=myData'
},
template :'<div class="inner" my-transclude></div>'
};
})
.directive('myTransclude', function() {
return {
restrict: 'A',
transclude: 'element',
link: function(scope, element, attrs, controller, transclude) {
transclude(scope, function(clone) {
element.after(clone);
})
}
}
});
As you can see, the transcluded bit doesn't appear. Any thoughts?
In this case you don't have to use a custom transclude directive or any trick. The problem I found with your code is that transclude is being compiled to the parent scope by default. So, you can fix that by implementing the compile phase of your directive (this happens before the link phase). The implementation would look like the code below:
app.directive('inner', function () {
return {
restrict: 'E',
transclude: true,
scope: {
source: '=myData'
},
template: '<div class="inner" ng-transclude></div>',
compile: function (tElem, tAttrs, transclude) {
return function (scope, elem, attrs) { // link
transclude(scope, function (clone) {
elem.children('.inner').append(clone);
});
};
}
};
});
By doing this, you are forcing your directive to transclude for its isolated scope.
Thanks to Zach's answer, I found a different way to solve my issue. I've now put the template in a separate file and passed it's url down through the scopes and then inserting it with ng-include. Here's a Plunk of the solution.
html:
<body ng-app="myApp" ng-controller="AppCtrl as app">
<outer model="app.data" row-template-url="template.html"></outer>
</body>
template:
<div>{{ source.name }}</div>
javascript:
angular.module('myApp', [])
.controller('AppCtrl', [function() {
var ctrl = this;
ctrl.data = { name: "Han Solo" };
}])
.directive('outer', function(){
return {
restrict: 'E',
scope: {
model: '=',
rowTemplateUrl: '#'
},
template: '<div class="outer"><inner my-data="model" row-template-url="{{ rowTemplateUrl }}"></inner></div>'
};
})
.directive('inner', function(){
return {
restrict: 'E',
scope: {
source: '=myData',
rowTemplateUrl: '#'
},
template :'<div class="inner" ng-include="rowTemplateUrl"></div>'
};
});
You can pass your transclude all the way down to the third directive, but the problem I see is with the scope override. You want the {{ source.name }} to come from the inner directive, but by the time it compiles this in the first directive:
template: '<div class="outer"><inner my-data="model"><div ng-transclude></div></div></div>'
the {{ source.name }} has already been compiled using the outer's scope. The only way I can see this working the way you want is to manually do it with $compile... but maybe someone smarter than me can think of another way.
Demo Plunker
Here is my code
'use strict';
angular.module('app')
.directive('item'
, ["$timeout"
, "$Service"
, function(
$timeout
, $utils) {
return {
restrict: 'A',
scope: {
item: '=',
},
transclude: true,
link: function(scope, element, attrs, ctrl, transclude){
},
templateUrl: $fsUtils.getRelativeUrl('templates/item.html'),
controller: 'ItemCtrl',
};
}]);
My index.html:
<item><div>Transcluded content.</div></item>
transclude variable is undefined and ctrl variable is proto__: Object.
I need to inject parent scope into transcluded scope. The transclude variable is undefined. Where am I going wrong.
My angular version is 1.1.5
Thanks.
What you're looking for is the transcludeFn. Try this:
transclude: true,
transcludeFn: function () { /*do your stuff here*/ },
...
link: function(scope, element, attrs, controller, transcludeFn)
To access controller in link function you can do this:
var controller = scope.controller;
I have a ng-repeat that will repeat a directive which does a $http call. then it will display the returned data, but I can't seem to stop the directives from updating each other. Here is the idea:
MAIN
...ng-repeat='item in itemList'...
... my-directive item="item.url"....
my-directive template
...{{result.count}}..
this returns the template updated only when the scope has changed.
.directive('myDirective', function($parse, $http) {
return {
restrict: 'E',
scope: {
item : '='
},
replace: true,
transclude: false,
templateUrl: '...template...',
controller: function($scope) {
$http.get(item.url).success(function(data) {
result.count=data.count;
})
}
at times, the result .count is the same through out the ng-repeat. I will like to know if I am doing something wrong, or maybe there is a way around this?
note: I have checked the results from the http call, and they are different all the time. also there are no syntax errors.
Use link in the directive and isolate your scope like:
.directive('myDirective', function($parse, $http) {
return {
restrict: 'E',
scope: true,
replace: true,
transclude: false,
templateUrl: '...template...',
link: function (scope, element, attrs) {
$http.get(attrs.item).success(function(data) {
scope.result.count=data.count;
}),
}
}
})
Read more about link and isolated scopes on https://docs.angularjs.org/guide/directive
Like someone said on comments using that is not the best way cos you a doing a GET for each item so if you have 10 items you will do a GET 10 times. If you can do the get 1 time on your controller and fetch all the data that you need.
With HTML like this...
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink}}<br>
<input my-dir ng-model="drink"></input>
</div>
</div>
and javascript like this...
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = 'water';
});
app.directive('myDir', function(){
return {
restrict: 'A',
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
Why can I not access the controller from within my directive? Why is my call to ctrl giving me undefined?
EDIT: add demo...
Fiddle available here: http://jsfiddle.net/billymoon/VE9dX/
see multiple controller can be attached with one app and simillarly multiple directive can be attached with one app, so if you wants to use one controller in one directive than you can set the controller property of directive to the name of the controller you wants yo attach with like in your case
app.directive('myDir', function(){
return {
restrict: 'A',
controller: 'inControl'
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
Despite this working with require:ngModel, this still isn't the best approach as it ties the directive directly to the controller. If you want your directive to communicate with your controller, you could be setting and reading off the scope.
HTML:
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink}}<br />
<input my-dir="drink"></input>
</div>
</div>
JS:
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = 'asdfasdf';
});
app.directive('myDir', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
console.log(scope[attrs.myDir]);
}
};
});
Alternatively you can use my-dir="{{drink}}" and read it as attrs.myDir.
http://jsfiddle.net/8UL6N/1/
Adding require: 'ngModel', fixed it for me - not sure if there is another way to specify it...
app.directive('myDir', function(){
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
I have 2 simple directives...
the parent directive:
.directive('modal', [function () {
return {
replace: true,
scope: {
/* attributes */
},
templateUrl: 'modal.tpl.html',
transclude: true,
link: function (scope) {
/* code */
}
};
the child directive
.directive('keypad', function () {
'use strict';
return {
templateUrl: 'keypad.tpl.html',
scope: {
value: '=',
},
link: function (scope, element, attrs) {
/* code */
}
};
and finally the controller:
.controller('ctrl', ['$scope', '$timeout', function ($scope, $timeout) {
$scope.$watch('howMuch', function(){
console.log('wont work ;-(');
});
}
and my template looks like this:
<div modal>
<div keypad class="keypad" value="howMuch"></div>
</div>
Any idea why the child directive can't change the howMuch value on the controller?
The same code but WITHOUT the parent directive works PERFECT.
The parent directive has an isolate scope. You didn't show the scope attributes, but howMuch needs to be accessed via a property in your isolated scope in order to update the value in the controller's scope.