i have seven div tags each
<div style="width:200px;height:100px" ng-controller="civCntlr">
You can use $rootScope.$broadcast + $rootScope.$on to communicate between controllers. For example,
var commApp = angular.module('CommApp', []);
commApp.controller('firstDivController', function($scope, $rootScope) {
$scope.class = "blue";
$scope.click = function() {
$rootScope.$broadcast("selected", "blue");
if ($scope.class === "blue") {
$scope.class = "active";
}
};
$rootScope.$on('selected', function(event, data) {
if (data !== "blue")
$scope.class = "blue";
});
});
commApp.controller('secDivController', function($scope, $rootScope) {
$scope.class = "green"
$scope.click = function() {
$rootScope.$broadcast("selected", "green");
if ($scope.class === "green") {
$scope.class = "active";
}
};
$rootScope.$on('selected', function(event, data) {
if (data !== "green")
$scope.class = "green";
});
});
commApp.controller('thirdDivController', function($scope, $rootScope) {
$scope.class = "red"
$scope.click = function() {
$rootScope.$broadcast("selected", "red");
if ($scope.class === "red") {
$scope.class = "active";
}
};
$rootScope.$on('selected', function(event, data) {
if (data !== "red")
$scope.class = "red";
});
});
commApp.controller('lastDivController', function($scope, $rootScope) {
$scope.class = "black"
$scope.click = function() {
$rootScope.$broadcast("selected", "black");
if ($scope.class === "black") {
$scope.class = "active";
}
};
$rootScope.$on('selected', function(event, data) {
if (data !== "black")
$scope.class = "black";
});
});
You can broadcast and listen on every controller like above.
However, just applying class is only your requirement, you can add and remove class dynamically.
$scope.click = function() {
angular.element(document.getElementsByClassName('active')).removeClass('active');
angular.element(document.getElementsByClassName('blue')).addClass('active');
};
It is always good to use service to communicate between controllers. I have done a small demo to show how to communicate between controllers using a service.
When ever data/some flag is changed then save it to the service. Your service should broadcast the changes to all the controllers. You then get the data from the service and change the view accordingly.
angular.module('myApp', []);
angular.module('myApp').controller('firstDivController', function($scope, service) {
$scope.divColor = (service.getId() == 'one' ? "green" : "red");
$scope.click = function() {
alert('Ctrl One');
service.setId('one');
};
$scope.$on('id', function() {
$scope.divColor = (service.getId() == 'one' ? "green" : "red");
});
});
angular.module('myApp').controller('secDivController', function($scope, service) {
$scope.divColor = (service.getId() == 'two' ? "green" : "red");
$scope.click = function() {
alert('Ctrl two');
service.setId('two');
};
$scope.$on('id', function() {
$scope.divColor = (service.getId() == 'two' ? "green" : "red");
});
});
angular.module('myApp').service('service', function($rootScope) {
var divId = 'one';
this.getId = function() {
return divId;
};
this.setId = function(id) {
divId = id;
this.broadcastId();
};
this.broadcastId = function() {
$rootScope.$broadcast('id');
};
});
Update:
After suggestion from #Cyril Gandon I have updated the code by removing the broadcast.
Working Plunker
Use ng-style and then use condition (ternary operator) inside ng-style
You should use a service when you need controller communicating.
Read this article on anti-patterns:
Only use .$broadcast(), .$emit() and .$on() for atomic events
Events that are relevant globally across the entire app (such as a user authenticating or the app closing). If you want events specific to modules, services or widgets you should consider Services, Directive Controllers, or 3rd Party Libs
$scope.$watch() should replace the need for events
Injecting services and calling methods directly is also useful for direct communication
Directives are able to directly communicate with each other through directive-controllers
// Code goes here
angular.module('myApp', []);
angular.module('myApp').service('activeService', function($rootScope) {
var activeId = 'one';
this.isActive = function(id) {
return activeId == id;
};
this.setActive = function(id) {
activeId = id;
};
});
angular.module('myApp').controller('firstDivController', function($scope, activeService) {
var id = 'one';
$scope.click = function() {
activeService.setActive(id);
};
$scope.getDivColor = function() {
return activeService.isActive(id) ? 'active' : 'blue';
};
});
angular.module('myApp').controller('secDivController', function($scope, activeService) {
var id = 'two';
$scope.click = function() {
activeService.setActive(id);
};
$scope.getDivColor = function() {
return activeService.isActive(id) ? 'active' : 'green';
};
});
angular.module('myApp').controller('thirdDivController', function($scope, activeService) {
var id = 'three';
$scope.click = function() {
activeService.setActive(id);
};
$scope.getDivColor = function() {
return activeService.isActive(id) ? 'active' : 'red';
};
});
angular.module('myApp').controller('lastDivController', function($scope, activeService) {
var id = 'last';
$scope.click = function() {
activeService.setActive(id);
};
$scope.getDivColor = function() {
return activeService.isActive(id) ? 'active' : 'black';
};
});
.green {
background-color: green;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
.black {
background-color: black;
}
.active{
background-color: yellow ;
}
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
</head>
<body>
<div style="width:200px;height:30px"
ng-controller="firstDivController"
ng-click="click()"
ng-class="getDivColor()">
<center>Hello , your in first box</center>
</div>
<div style="width:200px;height:30px"
ng-controller="secDivController"
ng-click="click()"
ng-class="getDivColor()">
<center>Hello , you are in second box</center>
</div>
<div style="width:200px;height:30px"
ng-controller="thirdDivController"
ng-click="click()"
ng-class="getDivColor()">
<center>Hello , you are in third box</center>
</div>
<div style="width:200px;height:30px"
ng-controller="lastDivController"
ng-click="click()"
ng-class="getDivColor()">
<center>Hello , you are in last box</center>
</div>
</body>
</html>
Related
I have the service :
service.getMarketedPrograms = function() {
return $http.get( archApiUrl + "program/marketed-program" ).then(function( result ) {
return result.data;
});
};
I want to append the service with the above :
service.getEligibility = function( params ) {
return $http.get( maverickApiUrl + "quote/getEligibility", { params: params }).then( transformEligibility );
};
After merging I want to filter the final one
If I understand correctly, you need to get both results firstly and then decide what to return.
You need to inject $q service (angularjs promises) and then use such code:
var promises = [getMarketedPrograms(), getEligibility()];
$q.all(promises).then(function(results){ //array of results
console.log(results[0]); //marketedPrograms result
console.log(results[1]); //getEligibility result
return results[0]; //for example, or do whatever you need
})
If you have two different controllers and two services, to synchronize them all, you should use events mechanism, i.e. $broadcast and $on methods. So, whenAllDone function will be called only when both controllers have done their tasks($scope.self = true):
function controllerFactory(timeout, name){
return function($scope, $timeout){
var self = this;
var outerResult;
$scope.name = name;
whenAllDone = (data) => {
console.log(`Sync ${name} - selfResult: ${timeout}, outerResult: ${data}`);
}
$scope.$on('done', (x, arg) => {
if(arg.ctrl != self){
$scope.outer = true;
outerResult = arg.val;
if($scope.self)
whenAllDone(arg.val);
}
});
//mimic for getEligibility and getMarketedPrograms
$timeout(() => {
$scope.self = true;
$scope.$parent.$broadcast('done', { ctrl: self, val: timeout });
if($scope.outer)
whenAllDone(outerResult);
}, timeout);
}
}
angular.module('app', [])
.controller('ctrl1', controllerFactory(2000, 'ctrl1'))
.controller('ctrl2', controllerFactory(5000, 'ctrl2'))
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
<script type="text/ng-template" id="myTemplate">
<h4>{{name}}:</h4>
<span ng-style="{'background-color': self ? 'green' : 'white'}">self</span>
<span ng-style="{'background-color': outer ? 'green' : 'white'}">outer</span>
</script>
<div ng-controller='ctrl1' ng-include="'myTemplate'"></div>
<div ng-controller='ctrl2' ng-include="'myTemplate'"></div>
</div>
I have a html like this :
<div id="create-group" ng-controller="groupCreateController">
<div id="container">
<h1>Create group</h1>
<div class="row">
<div class="col-md-4"><input placeholder="Group Name.." ng-model="group.name"></div>
<div class="col-md-8">
<label>Group Description : </label>
<textarea ng-model="group.description"> </textarea>
</div>
</div>
<br/>
<div class="row">
<div class="col-sm-6">
<usermgr-permission-list group="group"></usermgr-permission-list>
<button type="button" class="btn btn-md btn-primary" ng-click="btnSave_click($event)">SAVE</button>
</div>
<div class="col-sm-6">
<usermgr-user-list group="group"></usermgr-user-list>
</div>
</div>
</div>
</div>
My controller is :
(function (module) {
'use strict';
module.controller('groupCreateController', function ($scope, $rootScope, $routeParams, $location, userGroupService, $mdDialog) {
$scope.group = [];
$scope.init = function () {
if ($routeParams.hasOwnProperty('id')) {
//edit mode
// $scope.trans.heading = 'Edit Release';
// $scope.trans.saveBtn = 'Save';
var id = parseInt($routeParams.id);
getUserGroup(id);
} else {
$scope.group[0].id = 0;
$scope.group[0].permissions = [];
$scope.assignedPermissions = [];
$scope.enrolledUsers = [];
$scope.group[0].users = [];
$scope.group[0].name = '';
$scope.group[0].description = '';
}
};
function getUserGroup(id) {
userGroupService.getbyid(id).then(function (info) {
if (info !== undefined && info.id === id) {
$scope.group[0].id = info.id;
$scope.group[0].name = info.name;
$scope.group[0].description = info.description;
console.log($scope.group);
// $rootScope.$broadcast('rCube-user-mgt-users-list', info.id);
// $rootScope.$broadcast('rCube-user-mgt-permissions-list', info.id);
}
else {
}
}).catch(function (exception) {
console.error(exception);
});
}
$scope.init();
});
})(angular.module('r-cube-user-mgt.user-group'));
I have two custom directives in the first block of code for user permissions and users. The group scope that i pass with the directive does not contain the values i put in the getUserGroup(id) function. The group name and group description shows up so the scope.group in the controller is filled, however thats not the case once i pass it to my directives. here is the directives code as well :
permissions list :
(function (module) {
'use strict';
module.directive('usermgrPermissionList', function () {
return {
restrict: 'E',
scope:{
group: '='
},
controller: function ($scope, permissionService) {
$scope.updatedPermissions=[];
console.log($scope.group); //it doesnt have the values from the controller ..
if (!$scope.group.hasOwnProperty('permissions')) {
$scope.group.permissions = [];
}
function getData() {
console.log("inside getDAta for permission list" + $scope.group.id;
permissionService.getPermissionsFiltered($scope.group.id).then(function (info) {
if (info && info.length > 0) {
console.log(info);
$scope.group.permissions = info.map(function (a, index, array) {
return {
id: a.id,
name: a.name,
description: a.description,
assigned: a.assigned
};
});
}
}).catch(function (exception) {
console.error(exception);
});
} //end of getData()
$scope.init = function () {
getData();
};
$scope.init();
},
templateUrl: 'r-cube-user-mgt/permission/list/list.tpl.html'
};
});
})(angular.module('r-cube-user-mgt.permission'));
can anyone help?
you cannot assign property to an array like this $scope.group.id = 0;
either make $scope.group object
$scope.group = {};
or add properties to an index
$scope.group = [];
$scope.init = function () {
if ($routeParams.hasOwnProperty('id')) {
//edit mode
// $scope.trans.heading = 'Edit Release';
// $scope.trans.saveBtn = 'Save';
var id = parseInt($routeParams.id);
getUserGroup(id);
} else {
$scope.group[0].id = 0;
$scope.group[0].permissions = [];
$scope.assignedPermissions = [];
$scope.enrolledUsers = [];
$scope.group[0].users = [];
$scope.group[0].name = '';
$scope.group[0].description = '';
}
};
So I solved the issue by adding broadcast to send the id when the directive loads. This worked!
in the Group controller i add broadcast and send the group.id
function getUserGroup(id) {
userGroupService.getbyid(id).then(function (info) {
if (info !== undefined && info.id === id) {
$scope.group.id = info.id;
$scope.group.name = info.name;
$scope.group.description = info.description;
console.log($scope.group);
$rootScope.$broadcast(rCubeTopics.userMgtPermissionLoadData, $scope.group.id);
}
}).catch(function (exception) {
console.error(exception);
});
}
and in the permission directive get that broadcast :
$scope.$on(rCubeTopics.userMgtPermissionLoadData, function (event, id) {
console.log($scope.group.id);
getData();
});
I am having an example of what i want to achieve given below in plunker.As 10 changes on right click,i want an image there that should convert to some another image on right click.Please help me out with this.
http://jsfiddle.net/bcaudan/vTZZ5/
app.directive('ngRightClick', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.ngRightClick);
element.bind('contextmenu', function(event) {
scope.$apply(function() {
event.preventDefault();
fn(scope, {$event:event});
});
});
};
});
made this fiddle for you: JsFiddle
Are you looking for something like this??
JS should be like this:
var app = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.img1 = "http://4.bp.blogspot.com/-JOqxgp-ZWe0/U3BtyEQlEiI/AAAAAAAAOfg/Doq6Q2MwIKA/s1600/google-logo-874x288.png";
$scope.img2 = "http://www.socialtalent.co/wp-content/uploads/blog-content/so-logo.png";
$scope.selected = $scope.img1;
$scope.increment = function() {
$scope.selected = $scope.img1;
};
$scope.decrement = function() {
$scope.selected = $scope.img2;
};
};
app.directive('ngRightClick', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.ngRightClick);
element.bind('contextmenu', function(event) {
scope.$apply(function() {
event.preventDefault();
fn(scope, {$event:event});
});
});
};
});
and HTML should be:
<div ng-app="myApp" ng-controller="MyCtrl">
<span class="action"
ng-click="increment()"
ng-right-click="decrement()"><img ng-src="{{selected}}"></span>
</div>
Please see demo below
var app = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.images = [
'http://upload.wikimedia.org/wikipedia/commons/a/a7/Tiffanie_at_cat_show.jpg',
'http://www.thetimes.co.uk/tto/multimedia/archive/00342/114240651_cat_342943c.jpg'
];
$scope.imageSrc = 1;
$scope.toggleImage = function() {
$scope.imageSrc == 1 ? $scope.imageSrc = 0 : $scope.imageSrc = 1;
};
};
app.directive('ngRightClick', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.ngRightClick);
element.bind('contextmenu', function(event) {
scope.$apply(function() {
event.preventDefault();
fn(scope, {
$event: event
});
});
});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<image ng-src="{{images[imageSrc]}}" class="action" ng-right-click="toggleImage()" width="150px" />
</div>
I'm writing an app with Ionic and the $cordovaSQLite plugin. I have this simple controller
.controller('TopicCtrl', ['$scope', '$stateParams', 'Topic', function($scope, $stateParams, Topic) {
$scope.topic = null;
Topic.get($stateParams.topicId).then(function(data) {
$scope.topic = data;
});
}]);
for this simple view
<ion-view view-title="{{topic.title}}">
<ion-content>
...
</ion-content>
</ion-view>
The problem is $scope.topic remains null the first time I display this view (therefore no title for this view is displayed), when I navigate to another view and then press the back button $scope.topic has the fetched data so the topic's title is displayed on the view. Why is $scope.topic not updated as expected?
My services.js looks like this
.factory('SQLiteService', ["$q", "$interval", "$cordovaSQLite", "$ionicPlatform", function($q, $interval, $cordovaSQLite, $ionicPlatform) {
var self = this;
self.db = null;
self.init = function() {
window.plugins.sqlDB.copy("database.db", function () {
self.db = window.sqlitePlugin.openDatabase({name: "database.db", bgType: 1, createFromLocation: 1, location: 2});
}, function (e) {
self.db = window.sqlitePlugin.openDatabase({name: "database.db", bgType: 1, createFromLocation: 1, location: 2});
});
};
self.query = function(query, bindings) {
var wrapper = function() {
bindings = typeof bindings !== 'undefined' ? bindings : [];
var deferred = $q.defer();
$ionicPlatform.ready(function () {
$cordovaSQLite.execute(self.db, query, bindings).then(function(data) {
deferred.resolve(data);
}, function(error) {
deferred.reject(error);
});
});
return deferred.promise;
};
if (!self.db) {
var q = $q.defer();
$interval(function() {
if (self.db) {
q.resolve();
}
}, 100, 25);
return q.promise.then(function() {
return wrapper();
});
}
return wrapper();
};
self.fetch = function(data) {
return data.rows.item(0);
};
return self;
}])
.factory('Topic', ["SQLiteService", function(SQLiteService) {
var self = this;
self.get = function(id) {
var query = "SELECT id, title FROM topics WHERE id = ?";
return SQLiteService.query(query, [id]).then(function(data) {
return SQLiteService.fetch(data);
});
}
return self;
}]);
i had same issue, i solved by using alternative directives for view title as
<ion-view cache-view="false">
<ion-nav-title>{{topic.title}}</ion-nav-title>
<ion-content>
...
</ion-content>
and make sure cache is off for this view
I am having one chart directive created, and I am bootstrpping the app after loading google api. In following code, a simple data table is working fine. But when I load data from server in async manner, chart is not being displayed.
Controller
'use strict';
myNetaInfoApp.controller('allCandidatesController', [
'$scope','allCandidates2009Svc', '$timeout',
function ($scope, allCandidates2009Svc, $timeout) {
$scope.data1 = {};
$scope.data1.dataTable = new google.visualization.DataTable();
$scope.data1.dataTable.addColumn("string", "Party");
$scope.data1.dataTable.addColumn("number", "qty");
$scope.data1.dataTable.title = "ASDF";
$timeout( function (oldval, newval) {
allCandidates2009Svc.GetPartyCriminalCount().then(function(netasParty) {
var i = 0;
for (var key in netasParty) {
$scope.data1.dataTable.addRow([key.toString(), netasParty[key]]);
i++;
if (i > 20) break;
}
});
});
$scope.dataAll = $scope.data1;
//sample data
$scope.data2 = {};
$scope.data2.dataTable = new google.visualization.DataTable();
$scope.data2.dataTable.addColumn("string", "Name");
$scope.data2.dataTable.addColumn("number", "Qty");
$scope.data2.dataTable.addRow(["Test", 1]);
$scope.data2.dataTable.addRow(["Test2", 2]);
$scope.data2.dataTable.addRow(["Test3", 3]);
}
]);
Service
'use strict';
myNetaInfoApp.factory('allCandidates2009Svc', ['$http', '$q',
function ($http, $q) {
var netas;
return {
GetPartyCriminalCount: function () {
var deferred = $q.defer();
$http.get('../../data/AllCandidates2009.json')
.then(function (res) {
netas = res;
if (netas) {
var finalObj = {};
_.each(netas.data, function(neta) {
finalObj[neta.pty] = finalObj[neta.pty] ? finalObj[neta.pty] + 1 : 1;
});
deferred.resolve(finalObj);
}
});
return deferred.promise;
}
};
}]);
Directive
"use strict";
var googleChart = googleChart || angular.module("googleChart", []);
googleChart.directive("googleChart", function () {
return {
restrict: "A",
link: function ($scope, $elem, $attr) {
var dt = $scope[$attr.ngModel].dataTable;
var options = {};
if ($scope[$attr.ngModel].title)
options.title = $scope[$attr.ngModel].title;
var googleChart = new google.visualization[$attr.googleChart]($elem[0]);
$scope.$watch($attr.ngModel, function (oldval, newval) {
googleChart.draw(dt, options);
});
}
};
});
HTML
<div ng-controller="allCandidatesController">
<div class="col-lg-6">
<h2>Parties and Candidates with Criminal Charges</h2>
<div google-chart="PieChart" ng-model="dataAll" class="bigGraph"></div>
<!--<p><a class="btn btn-primary" href="#" role="button">View details ยป</a></p>-->
</div>
<div class="col-lg-6">
<h2>Heading</h2>
<div google-chart="BarChart" ng-model="data2" class="bigGraph"></div>
</div>
</div>
I think you need to wrap your function body in allCandidates2009Svc factory with scope.$apply(). But the return deferred.resolve() will be outside scope.$apply().
function asyncGreet(name) {
var deferred = $q.defer();
setTimeout(function() {
// since this fn executes async in a future turn of the event loop, we need to wrap
// our code into an $apply call so that the model changes are properly observed.
scope.$apply(function() {
deferred.notify('About to greet ' + name + '.');
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
});
}, 1000);
return deferred.promise;
}
Read the docs here
http://docs.angularjs.org/api/ng.$q