I have a problem with getting updated value between in different page controller, Here is the situation.
page1.html
<body ng-app="app">
<div ng-controller="ctrl1">{{ version }}</div>
</body>
page2.html
<body ng-app="app">
<div ng-controller="ctrl2">{{ version }}</div>
</body>
app.js
var app = angular.module("app", []);
app.run(function($rootScope) {
$rootScope.Data = [];
$rootScope.Data.Version = '1.0.0.1';
});
app.controller('ctrl1', function($scope, $rootScope){
$scope.version = $rootScope.Data.Version;
$rootScope.Data.Version = '1.0.0.2';
});
app.controller('ctrl2', function($scope, $rootScope){
$scope.version = $rootScope.Data.Version;
});
Result
version: 1.0.0.1 // page1.html
version: 1.0.0.1 // page2.html
Expected Result
version: 1.0.0.1 // page1.html
version: 1.0.0.2 // page2.html
How to achieve this kind situation?
I tried using $broadcast from this tutorial for seprate page controllers: fiddle
You can't just reload pages without losing all your data, you know that? Your $rootScope dies, everything dies... :) Your example is completely wrong. Either use SPA routing which doesn't force browser reload or use some type of local storage for keeping the data safe.
Also I have noticed that you are binding to primitives $scope.version = $rootScope.Data.Version; - don't do that, use $scope.data = $rootScope.Data; and then {{data.Version}}. Anyway you should not be using $rootScope at all.
Pass the values between controller use broadcast and on method. please refer the link http://www.dotnet-tricks.com/Tutorial/angularjs/HM0L291214-Understanding-$emit,-$broadcast-and-$on-in-AngularJS.html
You know what I found after using Angular for 2 years now, that using direct variables like $scope.version is not the best for Angular, because they add different watches and in your case you are rewriting instance of 'version'.
Anyway, try to write like that everything what is getting synchronized between different controllers, services, directives, and so on.
var state = {
version: $rootScope.Data.Version,
anyOtherVariable: value
};
$scope.state = state;
Related
I am trying to fetch some data from server before controller get render.
I have found many answers for it with respect to routeProvider.
But my main issue is my controller does not bound with any route.
So is there any way to make this possible?
I have controller in following ways...
<!-- HERE I WANT TO BLOCK RENDERING TILL DATA GET LOAD -->
<AppController>
<ng-view>
</AppController>
It sounds like a resolve is what you are looking for, but if you are not using a routing table for this controller, you'll not have this option. Why not just resolve an asynchronous call in your controller, and set scope variables inside the callback. This is what I interpret your desire to await controller "rendering", whereas a resolve through a route table would await controller instantiation. Observe the following...
module.controller('ctrl', function($scope, $http) {
$http.get('/uri').then(function(response) {
// set $scope variables here
});
console.log('executed first');
});
You could also set a variable to prevent the associated view from rendering if your data call is lengthy. This would prevent the UI from "dancing." Observe the following changes to the above example...
<div ng-controller="ctrl" ng-show="resolved"></div>
module.controller('ctrl', function($scope, $http) {
$http.get('/uri').then(function(response) {
$scope.resolved = true; // show rendering
});
});
JSFiddle Link - simplified demo
JSFiddle Link - demo ng-if
One idea will work
in html controller:
<p ng-if="notLoadedContent">Wait</p>
<div ng-if="!notLoadedContent">Content fetched</div>
And in Controller all controller is inside one function will start all, and the controller will be :
fetch(init)
$scope.notLoaded = true;
function init(){
$scope.notLoaded=false;
}
hope it help you
Below is a piece of code that connects with a Firebase database.
I have got a value for numberOfUsers and now I would like to use this variable in the html like so {{numberOfUsers}}.
I'm not really sure the best way to do this or if I need to use controllers also? Sorry if it's a stupid question, I'm still learning Javascript and Angular.
angular.module('myApp', ['ngRoute', 'firebase'])
var userList = new Firebase("https://my-app.firebaseio.com/presence/");
userList.on("value", function(snap) {
numberOfUsers = snap.numChildren();
console.log("Users = " + numberOfUsers);
});
;
http://jsfiddle.net/HB7LU/11820/
Any help will be much appreciated.
Thanks
The formal way to make a value available would be to put it in $rootScope, but it might be better to expose it as part of a service.
Try using constant
http://jsfiddle.net/HB7LU/11818/
var myApp = angular.module('myApp',[]);
myApp.constant('numUsers', 4);
function MyCtrl($scope,numUsers) {
$scope.name = 'Superhero';
$scope.numUsers = numUsers;
$scope.addUser = function(){
numUsers++;
$scope.numUsers = numUsers;
}
}
You can use a constant to achieve the same as Lucas suggested it. However, instead of creating a constant service for every value you can group then together like this :
angular.module("myModule")
.constant("CONST", { "KEY1" : "VALUE1",
"KEY2" : "VALUE2"});
This way you can gather a bunch of constants together and use it like:
CONST.KEY1
CONST.KEY2
EDIT: Your problem seems to be very different.
First of all you should use the AngularJS flavour of Firebase. Its called AngularFire. You can find out more about it here. I will answer the question of rendering the UI based on Model changes. AngularJS promotes the MVC pattern. You need objects of Service, Controller and View (HTML page) to achieve the functionality you want.
In the example I am providing below, everything is clubbed into one file (index.html) but ideally, the code should be separated.
<div ng-app="myapp">
<div ng-controller="PostCtrl" >
<ul>
<li ng-repeat="post in posts"> <!-- $scope.posts of PostCtrl" -->
<div>
<span>{{post}}</span> <!-- {{}} is used to render data -->
</div>
</li>
</ul>
</div>
<script>
//factory is a type of service. Services are used to write business logic or fetch data from the backend. Your Firebase related calls should come here.
angular.module("myapp", []).factory("myService", function($http) {
return {
fetchData: function() {
return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; //can also be a request to the backend returning data.
}
};
});
//a controller connects a service to the HTML file. $scope service provided by AngularJS is used to achieve this.
angular.module("myapp").controller("PostCtrl", ["$scope", "myService", function($scope, myService) {
//posts variable is used in HTML code to retrieve this data.
$scope.posts = myService.fetchData();
}]);
</script>
</div>
To learn the basics of AngularJS you can go through codeschool tutorials. They are interactive and start from the basics.
I've been working on a Chromium extension which sends data from a content script to another extension page which runs an Angular app. Since I separated my app into several controllers relying on a data service, I've run into a bug where sometimes my app's templates will all display correctly but other times it will not. In this simplified example, my app might display the data value on the page on a run and then not display it after refreshing the page and running the same code.
In the case when the data is not displayed, I can still inspect the DataService object at runtime and find the data value to be instantiated correctly.
app.js
angular.module('angularApp', [])
.controller('AppController', ['$scope', 'DataService',
function($scope, dataService) {
$scope.dataService = dataService;
}]);
service.js
var angularApp = angular.module('angularApp');
angularApp.service('DataService', function() {
var data = [];
chrome.runtime.onMessage.addListener(function(message, sender) {
var messageData = $.extend([], message.data);
// populate data array based on messageData
});
};
view.html
<html ng-app="angularApp">
<body ng-controller="AppController">
{{dataService.data}}
</body>
</html>
This seems to be an issue with the asynchronous arrival of the message from the content script, but I'm not sure of the appropriate way to solve this within my Angular service. An ideal answer would explain what is going on to cause my bug and the best practice to build my service and controllers to work as expected every time.
Your controller and view are fine. Your service should work if you do this:
angular.module('angularApp').service('DataService',['$timeout',
function($timeout){
var self = this;
this.data = [];
var tmp;
function handleMessage(){
//tmp == message.data
//populate self.data however..
}
chrome.runtime.onMessage.addListener(function(message,sender){
tmp = message.data;
$timeout(handleMessage);
});
}]);
The reason it isn't working currently is because the event handler isn't executing in angular's event loop. By doing the data manipulation in a $timeout it will force angular to update the view with the data that has changed.
Using $timeout essentially has the same effect as $scope.$apply() in this scenario
My problem is I have one ng-app. Does that mean I have to do dependency injection for plugins I may not be using on that given view? Example I bring in ngTagsInput does that mean I have to do it even when the view doesn't call for it? That would mean I have to include that js for every view even if it doesn't use ngTagsInput.
I have a very large MVC .NET application and I am trying to figure out what is he best way to handle bringing in external plugins.
I have some code like so in our Main _Layout template:
<html ng-app="ourApp">
<head>
<!-- all of our includes are here -->
</head>
<body>
<directive></directive>
<anotherdirective></anotherdirective>
#RenderBody()
</body>
</html>
RenderBody is where MVC slides in our views from our mvc routing.That view may look like so:
<script src="~/Scripts/HomeAngular.js"></script>
<div ng-controller="HomeCtrl">
<directive3></directive3>
</div>
App JS:
var app = angular.module('ourApp', ['ngTagsInput']);
IS there a way I can get around having to inject ngTagsInput on every view page even if i don't need it?
There are several different ways to handle Dependency Injection (DI) in angular. In this first example, you simply define ngTagsInput before declaring the controller. If ngTagsInput is a service, for example, you'll need to return an object with methods that allow you to access the data inside of that service.
For example:
app.service('ngTagsInput', function($scope) {
var data = {};
return {
getData = function() {
return data;
},
setData = function(val) {
data = val;
}
};
});
app.controller('HomeCtrl', function($scope, ngTagsInput) {
// ...
$scope.tags = ngTagsInput; // whatever you want to do with it
});
However, there's a problem...
In the example above, if you run that code through a minifier, you'll get $scope turned into some variable (a, b, x, etc...) and angular wont know what to do with that.
In this method, we use an array. The last item in your array is your lambda function for the controller, which takes 1 argument for each previous item in the array:
app.controller('HomeCtrl', ['$scope', 'ngTagsInput', function(scp, ngTagIn) {
// ...
}]);
This code can be run through a minifier just fine, since the dependencies are strings in the array and can be renamed to anything you want inside the function's parameters.
DI also works in directives, factories, filters, and services with the same syntax; not just controllers and modules.
app.directive('HomeCtrl', ['$scope', 'ngTagsInput', function(scp, ngTagIn) {
// ...
}]);
Couldn't you break down your application further into smaller modules instead of just one. Then you can inject the smaller modules into the app module and only inject the ngTagsInput dependency on the modules that actually need it. That's how I typically break up my application by function or area.
I want to reload a template and the connected Controller without using $routeProvider, because
my Path-structure doesn't fit with .when(...). I want to use $location.path() to read the URL and set the desired action.
But: if the path of the URL changes, the template doesn't automatically update and neither is the controller reloaded.
Is there a way to say something like this?
angular.module('myApp').controller('ctrl').reload()
I would suggest looking into the Angular UI Router written by the same guys who wrote angular. It will let you transition to different states which is what it sounds like you are trying to do.
https://github.com/angular-ui/ui-router
My solution: don't use Routes! Simply update a variable for your template, controllers don't need updates (simply update the data):
angular.module('myApp',[])
.run(['$rootScope', '$location', 'myService', function ($rootScope, $location, myService) {
$rootScope.view = "";
// Some function to read the URL
$rootScope.setRouting = function(){
var p = $location.path().split("/");
// Do things with p[0], p[1], ...
// e.g. if url is /post/123
$rootScope.view = p[0];
myService.setData(p[1]);
}
// Monitor Location changes:
$rootScope.$on('$locationChangeSuccess', function(event) {
$rootScope.setRouting();
});
// And this is useful for calling within template: ng-click="go('...')"
$rootScope.go = function(path){
$location.path(path);
}
}]);
And for the HTML:
<body>
<ng-include src="view + '.html'"></ng-include>
</body>