I am currently building an app. My view has been minified to this for presentation purposes:
<div class='reviews' ng-repeat="review in reviews">
<div><ratestar></ratestar></div>
</div>
I also have a directive that I built:
angular.module('LiveAPP.artist',[])
.controller('artistCtrl', ['$scope', '$http', '$location', 'dataFactory', '$routeParams', artistCtrl])
.directive("ratestar", function() {
return {
restrict: "E",
scope: {},
template: "<div id='rateYo'></div>",
link: function( scope, ele, attrs ) {
var $rateYo = $(ele).rateYo({
rating:***VARIES ACCORDING TO REVIEW***
});
}
};
});
function artistCtrl($scope, $http, $location, dataFactory, $routeParams){
$scope.reviews = [{num_of_stars:1},...,{num_of_stars:3}]
}
Essentialy I want the rating in rateYo({}) to be the num_of_stars from $scope.reviews. So when ng-repeat is run it takes each object from from $scope.reviews and assigns num_of_stars to rating. Anyone have any idea on how to tackle this? I had a feeling that adding class=$index to <ratestar></ratestar> might work, but it didn't.
Related
I am working on an old project where I use AngularJS 1.x and have trouble communicating to sibling scope
App.js
var myApp = angular.module('myApp', ['ui.router', 'headerModule', 'dashboardModule', 'profileData', 'roiData', 'eventData', 'LocalStorageModule']);
// Use Routes to Header Changes
myApp.run( ['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {
$rootScope.$on('callViewEvent', function(ev, x){
console.log("here"); //getting printed
$rootScope.$broadcast('vv',x);
});
}]);
I have a directive
eventData.js
var eventData = angular.module('eventData', ['angularPayments', 'ngFileUpload']);
eventData.directive('eventData', function () {
return {
restrict: 'EA',
scope: {},
replace: true,
link: function ($scope, element, attributes) {
},
controller: function ($scope, $attrs, $http, $state, $rootScope, $window, $interval, Auth, Upload) {
$scope.$on('vv', function(e, x){
console.log("event called");
$scope.viewEvent(x);
});
},
templateUrl: 'directives/event/eventData.tpl.html'
}
});
A controller module
dashboardController.js
var dashboardModule = angular.module('dashboardModule', []);
dashboardModule.controller('dashboardController', function($scope, $rootScope, $http, Auth, $state ) {
$scope.childmethod = function(x) {
console.log("click"+x);
$scope.$emit("callViewEvent", x);
}
});
I am emitting event from child to parent and then brodcasting into another child. Emit is working but broadcast is not working. That is the second event call is working
Please try:
$rootScope.$on('vv', function(e, x){
console.log("event called");
$scope.viewEvent(x);
});
The component that listens for the event is either not being instantiated or it is instantiated after the event is dispatched.
For debugging purposes, add a console.log to the component:
app.directive('eventData', function () {
return {
restrict: 'EA',
scope: {},
replace: true,
link: function ($scope, element, attributes) {
},
controller: function ($scope, $attrs, $http, $state, $rootScope, $window, $interval, Auth, Upload) {
//DEBUG TIMING
console.log("eventData controller instantiated");
$scope.$on('vv', function(e, x){
console.log("event called");
$scope.viewEvent(x);
});
},
templateUrl: 'directives/event/eventData.tpl.html'
}
});
Be aware that the $scope event bus is deprecated. Using it will make migration to Angular 2+ more difficult.
For more information, see
AngularJS Developer Guide - Component-based Application Architecture
I am using UI-Router and trying to access my web app's current state from within a directive, using the following:
footer.directive.js
(function () {
'use strict';
angular
.module('app')
.directive('myFooter', myFooter);
myFooter.$inject = ['$cookies', 'userFactory', '$state', '$log', '$rootScope'];
function myFooter($cookies, userFactory, $state, $log, $rootScope) {
var directive = {
restrict: 'E',
templateUrl: 'app/components/footer/footer.html',
controller: FooterController,
controllerAs: 'vm',
bindToController: true
};
return directive;
function FooterController($state) {
var vm = this;
vm.currentState = $state;
}
}
})();
footer.html
<div class="footer">
<p>{{ vm.currentState.current.name }}</p>
</div>
When I run $log.log($state) it posts an object in my console that has a current object with a name attribute that is equal to the state name that I need, but when I try to reference the $state.current.name, either on my view or by logging it to the console, it displays as an empty string.
I'm a bit new to Angular, so if someone could explain to me what is going on here or at the least how to fix this so that I can display what I want properly, that would be a huge help. Thanks!
Edit: Two other questions that I looked at before posting this one are:
This one which seems to deal more with changing a class name based on state name, and this one, which doesn't quite address my problem either (and doesn't look like it could possibly be the right way to do this.)
First of all, there is a naming bug in your posted code! (amaiFooter)
The second thing is, if you log an object, it's bound by a call by reference
So the moment you log it, you log the reference. That means when you look at it, it can contain other values than when you have logged it
But when you logged the state name and it was undefined, that was the right output!
You can try to wrap it in a $timeout function with 0 delay, just to add your code to the end of the current digest cycle, that should solve your problem
You need inject the state service on the controller as follows
(function () {
'use strict';
angular
.module('app')
.directive('myFooter', myFooter);
myFooter.$inject = ['$cookies', 'userFactory', '$state', '$log', '$rootScope'];
function myFooter($cookies, userFactory, $state, $log, $rootScope) {
var directive = {
restrict: 'E',
templateUrl: 'app/components/footer/footer.html',
controller: FooterController,
controllerAs: 'vm',
bindToController: true
};
return directive;
}
FooterController.$inject = ['$state'];
function FooterController($state) {
var vm = this;
vm.currentState = $state;
}
})();
I am creating a custom directive in a controller and calling it in ng-repeat as follows:
HTML:
<div ng-controller="TestCtrl">
<div ng-repeat="page in pages">
<custom
load-data="loadData = fn">
</custom>
</div>
</div>
JS:
Test directive is as follows:
scope: {
loadData: "&"
}
controller: ['$scope', '$element', '$timeout', '$filter', function ($scope, $element, $timeout, $filter) {
$scope.loadData({ fn: function(data) {
//Data calc.
}});
}
I am calling loadData from TestCtrl as follows:
App.controller('TestCtrl', function($scope, $http, $timeout, $rootScope) {
$scope.loadData(data);
}
In TestCtrl scope, loadData function is present if ng-repeat is not used and works fine but gives error as undefined is not a function at line where $scope.loadData(data) is called when ng-repeat is used.
Thanks in Advance
The controller of your directive is not correct, It's syntax is
controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }
$timeout, $filter should come after $attrs and $transculde. You need to include both even if you are not using it
Even after above changes, if there is still an issue, then we can check further, but the above has to be fixed or else you wont be able to use $timeout and $filter
I have directive that dynamically sets the header bar content for a given application state.
I would like to be able to access the functions and variables in the Controller of the current view, but I am only ever able to access my RootCtrl.
The directive looks like this.
return {
restrict: 'EA',
template: "<div ng-include='getState()'></div>",
transclude: true,
scope: false,
controller: ['$scope', '$state', function($scope, $state) {
//some logic to retrieve and return the correct header template html
}],
link: function(scope, element, attrs){
console.log(scope.test);
console.log(scope.test2);
}
}
And the controllers.
.controller('RootCtrl', function($scope, $state, $location, $rootScope) {
$scope.test = 'hello';
//...
})
.controller('ContactsCtrl', function($scope, $state, CustomerService) {
console.log('Contacts init');
$scope.test2 = 'hello 2';
//...
})
And when I navigate to the contacts state, the output looks like this.
hello
undefined
Contacts init
What should I do if I want to be able to access the test2 variable?
You will need to use the require property inside your directive.
This will make the scope of the defined controllers available inside the link function as 4th argument. You can access the scopes as an array inside the link function then.
Your code may look like:
return {
restrict: 'EA',
template: "<div ng-include='getState()'></div>",
transclude: true,
scope: false,
require:['^RootCtrl', '^ContactsCtrl'],
controller: ['$scope', '$state', function($scope, $state) {
//some logic to retrieve and return the correct header template html
}],
link: function(scope, element, attrs, requiredControllers){
console.log(requiredControllers[0].test);
console.log(requiredControllers[1].test2);
}
}
See the Angular documentation for Directives for some more examples (under the title Creating Directives that Communicate) and the explanation of the ^controller syntax.
first time asker. Apologies if my jargon isn't quite right I'm new to angularjs
I have a controller which gets a list of products with a HTTP call
contractManagementControllers.controller('PriceBandsCtrl', ['$scope', '$routeParams', '$http', '$location',
function ($scope, $routeParams, $http, $location)
{
$http.get('products').success(function (products)
{
$scope.productList = products
})
}
And a directive which I would like to have access to that product list.
contractManagementControllers.directive("priceBands",function($http)
{
return {
scope: true,
restrict: 'AE',
replace: 'true',
templateUrl: 'Partials/PriceBand.html',
link: function ($scope, ele, attrs, c)
{
// use $scope.productList
}
});
My issue is with the order in which things happen. The controller function runs first, followed by the directive link function, followed by the callback which sets the product list. As such $scope.productList is undefined in the directive link function and gives an error
Is there a way to force the link function to wait until the callback has completed?
Set default value to productList in order not get error about undefined variable
contractManagementControllers.controller('PriceBandsCtrl', ['$scope', '$routeParams', '$http', '$location',
function ($scope, $routeParams, $http, $location)
{
$scope.productList = [];
$http.get('products').success(function (products)
{
$scope.productList = products
})
}
and then watch for changes of the productList in directive:
contractManagementControllers.directive("priceBands",function($http)
{
return {
scope: true,
restrict: 'AE',
replace: 'true',
templateUrl: 'Partials/PriceBand.html',
link: function ($scope, ele, attrs, c)
{
$scope.watch('productList', function(newValue, oldValue) {
//Perform here if you need
});
}
});
no need of waiting for callback in angularjs. just put the $scope.productList=[]; in your controller as first line. it will not give undefined to directive.
In your directive link function just write the $watch function to watch changes in element.