Issues updating angular view from another controller - angularjs

In the below, I have a sidenav and a main content section. I am trying to call the sidenav function from the main controller so the number updtes in the sidenav. What am I doing wrong here?
This is my view.
<div>Teams {{ teams.length }} </div>
This is my sidebar controller:
angular.module('myApp').controller('leftNav', function($scope, myFactory) {
myFactory.getTeams().then(function(res) {
$scope.teams = res.data;
})
This is my factory
angular.module('myApp').factory('myFactory', function($http) {
return {
getTeams : function() {
return $http.get('/teams').then(function(res) {
return res;
});
}
};
});
This is a complete different controller:
angular.module('myApp').controller('main', function($scope,$http, myFactory) {
$http.post(...blablabl..).then(function() {
// What can i call here to update the sidenav above?
});
});

You can utilise $controller service to call your leftNav controller from your main controller like below
angular.module('myApp').controller('main', function($scope,$http, myFactory,$controller) {
$http.post(...blablabl..).then(function() {
var leftCTRL= $controller('leftNav', { $scope: $scope.$new() });
});
});

you can try like so :
angular.module('myApp').controller('leftNav', function($scope, myFactory) {
myFactory.getTeams().then(function(res) {
this.teams = res.data;
})
angular.module('myApp').controller('main', function($scope,$http, $controller) {
var leftNav= $controller('leftNav');
$http.post(...blablabl..).then(function(res) {
leftNav.teams = res.data;
});
});

Related

AngularJS broadcast data to iframe

How can I get the username from index.html?
index.html
{{username}}
index controller:
app.controller('index',function($scope,$rootScope,mainService){
$scope.getUsername = funciton(){
mainService.getUsername().then{
function successCallback(response){
$rootScope.username = response.data.username;
}
}
}
})
iframe.html
{{user}}
iframe controller
app.controller('iframe',function($scope,$rootScope){
$scope.user = $rootScope.username
})
but {{user}} show nothing
Also, I tried to post the message by Service like dataService.username result is the same.
Use $rootScope.$broadcast to raise an event, first paramter for the event name and an optional second parameter to pass an argument.
app.controller('IndexController', function ($scope, $rootScope, MainService) {
$scope.getUsername = function() {
MainService.getUsername().then(function (response) {
$rootScope.$broadcast('username-fetched', { username: response.data.username });
});
};
});
Then catch the event on the other controller by using $scope.$on.
app.controller('IframeController', function ($scope) {
$scope.$on('username-fetched', function (event, data) {
$scope.user = data.username;
});
});

Automatically update id variable in two controllers using $broadcast in AngularJS

$ctrl.clicker = function(id)
{
$rootScope.$broadcast('idBull', id);
}
When I mouseenter an image the above function gets called. I want to share the id in another controller and broadcast whatever changes where made to this id.
$scope.$on('idBull', function (event, data) {
console.log(data); // 'Data to send'
});
In the other controller I used the code to do a console loge of my id but got no results.
http://jsfiddle.net/87rLob9x/
Check this fiddle hope it helps
html
<html ng-app="myApp">
<div ng-controller='ControllerA'>
<button ng-click='add()'>Add</button
</div>
<div ng-controller='ControllerB'>
{{ increment }}
</div>
</html>
js:
var app = angular.module('myApp', [])
.controller('ControllerA', function($scope) {
$scope.increment = 0;
$scope.add = function() {
$scope.$broadcast('hasIncremented');
}
}).
controller('ControllerB', function($scope) {
$scope.$on('hasIncremented', function(event) {
$scope.increment++;
});
})
Not sure why you are not getting your code to work, maybe the controller with $scope.$on is not created/loaded when the $rootScope.$broadcast is executed?
Another solution is to use a service that you inject into both controllers and use that for communication instead. Example of broadcast solution:
var app = angular.module("app", [])
.controller("ControllerA", function($scope, $rootScope)
{
$scope.clicker = function(id)
{
$rootScope.$broadcast("id changed", id);
}
})
.controller("ControllerB", function($scope)
{
$scope.$on("id changed", function(event, id)
{
// Do whatever you need to do with id
});
});
Example of solution with custom service:
var app = angular.module("app", [])
.factory("customService", function()
{
var callbacks = [];
return {
onIdChange: function(callback)
{
callbacks.push(callback);
},
idChanged: function(id)
{
callbacks.forEach(function(callback)
{
callback(id);
});
}
};
})
.controller("ControllerA", function($scope, customService)
{
$scope.clicker = function(id)
{
customService.idChanged(id);
}
})
.controller("ControllerB", function(customService)
{
customService.onIdChange(function(id)
{
// Do whatever you need to do with id
});
});

How to call a method from a controller to another controller in angular js

I have a view for SidebarController like below -
<a ng-click="reachMe($event);$event.preventDefault()" ng-href="#/app/hello">
Before going to the link I want to call reachMe() to check some changes on page and need to show an alert if any changes made
function SidebarController($rootScope, $scope, $state, $location, SidebarLoader){
$scope.reachMe = function(event){
//here I want to call function isPageChanged() from StaticPageController
//something like this
// if StaticPageController.isPageChanged() return true
// then show alert
// else
// $location.url($href)
}
}
Update 1 :
Not sure about this, But give it a try.
<div ng-app="testApp" ng-controller="ControllerOne">
<button ng-click="methodA();"> Call Another Controller</button>
</div>
<script>
var app = angular.module('testApp', []);
app.controller('ControllerOne', function($scope, $rootScope) {
$scope.reachMe = function() {
var arrayData = [1,2,3];
$rootScope.$emit('callEvent', arrayData);
if($rootScope.isChanged){
// Show Alert
}else{
//Go to route
}
}
});
app.controller('ControllerTwo', function($scope, $rootScope,$state) {
$scope.checkSomethingChanged = function() {
alert("Hello");
$rootScope.isChanged = true;
}
$rootScope.$on('callEvent', function(event, data) {
console.log(data);
$scope.checkSomethingChanged();
});
});
Following method worked for me perfectly :
<div ng-app="testApp" ng-controller="ControllerOne">
<button ng-click="methodA();"> Call Another Controller</button>
</div>
<script>
var app = angular.module('testApp', []);
app.controller('ControllerOne', function($scope, $rootScope) {
$scope.methodA = function() {
var arrayData = [1,2,3];
$rootScope.$emit('callEvent', arrayData);
}
});
app.controller('ControllerTwo', function($scope, $rootScope) {
$scope.reachMe = function() {
alert("Hello");
}
$rootScope.$on('callEvent', function(event, data) {
console.log(data);
$scope.reachMe();
});
});
</script>
A controller is not the right concept for sharing functionality. Use a Factory or Service for that.
var logicFactory = function () {
return {
methodA: function () {
},
methodB: function()
{
}
};
}
You can then inject that factory into each controller where it is needed like:
var ControllerA = function ($scope,logicFactory) {
$scope.logic = logicFactory;
}
ControllerA.$inject = ['$scope', 'logicFactory'];
Another option is to use the broadcast/emit Patern. But I would use that only where really necessary:
Usage of $broadcast(), $emit() And $on() in AngularJS

Angular, show loading when any resource is in pending

I already write a code to display a loader div, when any resources is in pending, no matter it's getting via $http.get or routing \ ng-view.
I wan't only information if i'm going bad...
flowHandler service:
app.service('flowHandler', function(){
var count = 0;
this.init = function() { count++ };
this.end = function() { count-- };
this.take = function() { return count };
});
The MainCTRL append into <body ng-controller="MainCTRL">
app.controller("MainCTRL", function($scope, flowHandler){
var _this = this;
$scope.pageTitle = "MainCTRL";
$scope.menu = [];
$scope.loader = flowHandler.take();
$scope.$on("$routeChangeStart", function (event, next, current) {
flowHandler.init();
});
$scope.$on("$routeChangeSuccess", function (event, next, current) {
flowHandler.end();
});
updateLoader = function () {
$scope.$apply(function(){
$scope.loader = flowHandler.take();
});
};
setInterval(updateLoader, 100);
});
And some test controller when getting a data via $http.get:
app.controller("BodyCTRL", function($scope, $routeParams, $http, flowHandler){
var _this = this;
$scope.test = "git";
flowHandler.init();
$http.get('api/menu.php').then(function(data) {
flowHandler.end();
$scope.$parent.menu = data.data;
},function(error){flowHandler.end();});
});
now, I already inject flowHandler service to any controller, and init or end a flow.
It's good idea or its so freak bad ?
Any advice ? How you do it ?
You could easily implement something neat using e.g. any of Bootstrap's progressbars.
Let's say all your services returns promises.
// userService ($q)
app.factory('userService', function ($q) {
var user = {};
user.getUser = function () {
return $q.when("meh");
};
return user;
});
// roleService ($resource)
// not really a promise but you can access it using $promise, close-enough :)
app.factory('roleService', function ($resource) {
return $resource('role.json', {}, {
query: { method: 'GET' }
});
});
// ipService ($http)
app.factory('ipService', function ($http) {
return {
get: function () {
return $http.get('http://www.telize.com/jsonip');
}
};
});
Then you could apply $scope variable (let's say "loading") in your controller, that is changed when all your chained promises are resolved.
app.controller('MainCtrl', function ($scope, userService, roleService, ipService) {
_.extend($scope, {
loading: false,
data: { user: null, role: null, ip: null}
});
// Initiliaze scope data
function initialize() {
// signal we are retrieving data
$scope.loading = true;
// get user
userService.getUser().then(function (data) {
$scope.data.user = data;
// then apply role
}).then(roleService.query().$promise.then(function (data) {
$scope.data.role = data.role;
// and get user's ip
}).then(ipService.get).then(function (response) {
$scope.data.ip = response.data.ip;
// signal load complete
}).finally(function () {
$scope.loading = false;
}));
}
initialize();
$scope.refresh = function () {
initialize();
};
});
Then your template could look like.
<body ng-controller="MainCtrl">
<h3>Loading indicator example, using promises</h3>
<div ng-show="loading" class="progress">
<div class="progress-bar progress-bar-striped active" style="width: 100%">
Loading, please wait...
</div>
</div>
<div ng-show="!loading">
<div>User: {{ data.user }}, {{ data.role }}</div>
<div>IP: {{ data.ip }}</div>
<br>
<button class="button" ng-click="refresh();">Refresh</button>
</div>
This gives you two "states", one for loading...
...and other for all-complete.
Of course this is not a "real world example" but maybe something to consider. You could also refactor this "loading bar" into it's own directive, which you could then use easily in templates, e.g.
//Usage: <loading-indicator is-loading="{{ loading }}"></loading-indicator>
/* loading indicator */
app.directive('loadingIndicator', function () {
return {
restrict: 'E',
scope: {
isLoading: '#'
},
link: function (scope) {
scope.$watch('isLoading', function (val) {
scope.isLoading = val;
});
},
template: '<div ng-show="isLoading" class="progress">' +
' <div class="progress-bar progress-bar-striped active" style="width: 100%">' +
' Loading, please wait...' +
' </div>' +
'</div>'
};
});
Related plunker here http://plnkr.co/edit/yMswXU
I suggest you to take a look at $http's pendingRequest propertie
https://docs.angularjs.org/api/ng/service/$http
As the name says, its an array of requests still pending. So you can iterate this array watching for an specific URL and return true if it is still pending.
Then you could have a div showing a loading bar with a ng-show attribute that watches this function
I would also encapsulate this requests in a Factory or Service so my code would look like this:
//Service that handles requests
angular.module('myApp')
.factory('MyService', ['$http', function($http){
var Service = {};
Service.requestingSomeURL = function(){
for (var i = http.pendingRequests.length - 1; i >= 0; i--) {
if($http.pendingRequests[i].url === ('/someURL')) return true;
}
return false;
}
return Service;
}]);
//Controller
angular.module('myApp')
.controller('MainCtrl', ['$scope', 'MyService', function($scope, MyService){
$scope.pendingRequests = function(){
return MyService.requestingSomeURL();
}
}]);
And the HTML would be like
<div ng-show="pendingRequests()">
<div ng-include="'views/includes/loading.html'"></div>
</div>
I'd check out this project:
http://chieffancypants.github.io/angular-loading-bar/
It auto injects itself to watch $http calls and will display whenever they are happening. If you don't want to use it, you can at least look at its code to see how it works.
Its very simple and very useful :)
I used a base controller approach and it seems most simple from what i saw so far. Create a base controller:
angular.module('app')
.controller('BaseGenericCtrl', function ($http, $scope) {
$scope.$watch(function () {
return $http.pendingRequests.length;
}, function () {
var requestLength = $http.pendingRequests.length;
if (requestLength > 0)
$scope.loading = true;
else
$scope.loading = false;
});
});
Inject it into a controller
angular.extend(vm, $controller('BaseGenericCtrl', { $scope: $scope }));
I am actually also using error handling and adding authorization header using intercepting $httpProvider similar to this, and in this case you can use loading on rootScope
I used a simpler approach:
var controllers = angular.module('Controllers', []);
controllers.controller('ProjectListCtrl', [ '$scope', 'Project',
function($scope, Project) {
$scope.projects_loading = true;
$scope.projects = Project.query(function() {
$scope.projects_loading = false;
});
}]);
Where Project is a resource:
var Services = angular.module('Services', [ 'ngResource' ]);
Services.factory('Project', [ '$resource', function($resource) {
return $resource('../service/projects/:projectId.json', {}, {
query : {
method : 'GET',
params : {
projectId : '#id'
},
isArray : true
}
});
} ]);
And on the page I just included:
<a ng-show="projects_loading">Loading...</a>
<a ng-show="!projects_loading" ng-repeat="project in projects">
{{project.name}}
</a>
I guess, this way, there is no need to override the $promise of the resource

Load views after services in angularjs

In my angular app I have a view, a controller and a service.
The service load resources ex:service load persons and initialize value with the result.
I want to load my view after my service finish his function to load his resources.
var myApp = angular.module('myApp',[]);
myApp.controller('PersonsCtrl', ($scope, Persons) {
$scope.persons = Persons.data;
});
myApp.factory('Persons', {
data: [[function that load resources => take time]]
});
So I want to load my controller when my service finish his initialization.
Some ideas?
Assuming you have a route provider, here's a basic example. When the promise is resolved, "personData" will be injected into your controller. There's not much info about what your service does, so I had to give something very generic.
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/persons', {
controller: 'PersonsCtrl',
templateUrl: 'persons.html',
resolve: {
personData: ['Persons', function(Persons) {
return Persons.getData();
}]
}
});
}]);
myApp.controller('PersonsCtrl', ($scope, personData) {
$scope.persons = personData;
});
myApp.factory('Persons', {
getData: function() {//function that returns a promise (like from $http or $q)};
});
Maybe try using promises, example below
var myApp = angular.module('myApp',[]);
myApp.controller('PersonsCtrl', ($scope, Persons) {
$scope.persons = Persons.getData().then(function(response){
//do whatever you want with response
});
});
myApp.factory('Persons', function ($http, $q) {
return {
getData: function () {
var def = $q.defer();
$http.get('url').
success(function (response) {
def.resolve(response);
})
return def.promise();
}
}
});

Resources