Angularjs, do something when document loads - javascript

I am developing an angular js application, and i need to run a function, via service provider, before everything else. The function is a get request, which returns two variables in JSON, which returns either true orfalse.
If the variable is true, then load another state (i am using ui router). How can i do that?

In angular the document loaded is not really has a good usage, because it is a framework and the we need to count on angular loaded/ready instead. Use angular.module('yourApp').run() like below:
var app = angular.module('yourApp');
app.run(['$rootScope', '$http', function($rootScope, $http){
$http('http://localhost/status/').then(function(res){
$rootScope.somethingStatus = res; // assuming that your response is either true of false.
});
$rootScope.$watch('somethingStatus', function(nv){
// here is where you know your request has been done...
if(nv === true) {
// ...
}
else if(nv === false) {
// ...
}
});
}]);
NOTE: please aware what run in app.run() will be fired before any controller initialing or view rendering. So later on when you want to access the value of what you been got. Inject $rootScope to the controller (or any place) when you needed it.
EDIT: fix some typos. Updated answer again, credit to #georgeawg and #Pierre Emmanuel Lallemant. Thanks you guys for the correction

You should write a controller for the page where you do the request (in order to display something to the user), with a default html view, and when you receive the response, then you change the state to use the desired controller.

Related

AngularJS Router invoke function when certain URL is loaded initially

I am using angular router` to track the state of my web app like this:
when('/', {
controller: "AController",
templateUrl: "APanel.html"
}).
when('/subpage/:id', {
controller: "BController",
templateUrl: "BPanel.html"
}).
And I am using Angular Service to track some shared values:
app.service('stateService', function() {
this.someSwitch = false;
this.someLongDataArray = [x, y, z];
});
Currently, before changing path to \subpage\:id url from AController, I will assign new values to members of the service, so they can be referenced in subpages.
Now the question is, if user directly launching the subpage url \subpage\:id, or hit the refresh button on browser on subpage, BController will be invoked, and I will lost the values in the service which are supposed to be prepared by AController.
I am wondering what I should do in this case. is there any way I can get called when user launch the subpage directly, so I have a chance to prepare the data? (Maybe I can watch for html onload event, but not sure that's the best answer).
Thanks
It appears, BController is dependent on AController.
Ideally, Controller should not contain any data/dom manipulaton, state maintenance. It is simply a glue between view and the $scope model.
Being said so, you need not create any such dependency between controllers. The service can be invoked from both controllers.
OR
If indeed there is a requirement that APanel.html must be loaded/initialized before BPanel.html is loaded, then you must check for some flag in BContoller and redirect user to APanel.html.
like
if(<check some flag>){
$location.path('/');
}
But then you have to find the way to redirect the user again to BPanel.html. I guess this is not a recommended approach.
I am not sure I get your question completely. But if there is a possibility that the user might hit BPanel.html directly then you should do something like this.
if(serviceExists()){
//Do your usual Bcontroller stuff here if the services was initialized
}
else{
//Show a warning/error like "Oops, something is wrong go back to '/'" OR
// Initialize services in BController
}
This should be in your BController if initializing your service before BController is that important. You basically force people to stay on AController.

Angular ngRoute conditional .when()

I'd like to implement a conditional .when(), like this:
.when('/abc', {
// if MyService.allow == true
template: '<myDirec></myDirec>'
// else
redirectTo: '/'
})
My /abc route shall be like "secured" by a variable hold in one of my services, in a stateful manner. So I want to set this very state somewhere else to true/false and the next time the user tries to get to /abc he will be served conditionally.
How can I achieve this? - with as few 3rd-party dependencies as possible
What I tried and read about:
- Simply injecting my Service in .config, which I learnt is not possible
- Read about using a provider as they can be injected. But can I use them like I use my service?
- template and templateUrl accept a function, but this didn't really help me
Thanks very much in advance!
You could use the $routeChangeStart event. It's fired when the url is changed and takes current and next as arguments something like:
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if (next === 'abc') // do something;
});

angular how to use scope from a different controller

I have a user.list.ctrl and a user.detail.cntr. All the controllers are build as a module and are injected in a "user-module" which I inject in the app.js. (see the complete code in the plunker below)
my controller module
angular.module('user-module', ['user-module.controllers']);
my user-module
angular.module('demo.app', ['user-module']);
In both controllers i inject user-Fctr with data from a REST factory. (works well)
user.list.cntrl has a $scope.refresh()
user.detail.cntrl has a $scope.update()
user.list.cntrl
When I enter a new record, i call the $scope.refresh() so I can refresh the list. (this is working fine)
user.detail.cntrl
When i click a user from the list, the user detail loads in a different view (works ok)
when I update the user.detail, I want to call $scope.refresh() to update the user.list , but it is not working. I cannot call $scope.refresh()
I thought that since I inject the same factory into both controllers I can use each others $scopes.
Any ideas on how I can use $scope.refresh() (or update the list when I update the user.detail.js)
I make a plunker with all the js files (the plunker is not functional, it is only to show the code that I have)
http://plnkr.co/edit/HtnZiMag0VYCo27F5xqb?p=preview
thanx for taking a look at this
This is a very conceptual problem.
You have created a controller for each "piece" of view because they are meant for different activities. This is the purpose of controllers. So that is right.
However, you are trying to access the refresh function, written in one controller, in another one. Taken literally, this is wrong, since then, refresh is out of place either inside the user list controller or the detail controller.
A function that is meant to control (literally) what is happening on a specific piece of view is a controller. - There you are right having a controller for the list and one for the details.
A function that is meant to be shared between controllers must be a service. This is exactly what you want for your refresh function to be.
Whenever you inject the same factory into n controllers, you can't use the scope of every controller. This isn't the purpose of a controller.
However, whenever you inject the same factory into n controllers, you can use its exposed methods.
The problem you have, can be solved as follows:
app.factory( 'sharedFunctions', [ 'factoryId', function sharedFunctions( factoryId ) {
var refresh = function () {
factoryId.getAll(/*your params to query*/)
.success( function ( response ) {
//This will return the list of all your records
return response;
});
};
return sharedFunctions;
}]);
With this factory service registered, then you can inject it to your controllers and whenever you need to refresh, just call the exposed method of the service and plot the new information into the view.
Hope it works for you!
i ended up doing this:
I added in the list.contrl this:
factoryId.listScope = $scope;
since I already have the factoryId (my data service) injected in the detail controller, I can call this:
factoryId.listScope.refresh();
it works but I don't know if this is the best way. any comments?

How to store/communicate global asynchronous data to controllers

The basic premise is this....
I have an application. When the user hits the application, it immediately fetches various information regarding the user from a sharepoint server through an ajax call. And depending on what kind of data is received from the user, the app has to display/hide certain information and set certain settings.
Each controller within the application is heavily dependent on the data that is returned from this sharepoint server.
I have several questions...
First, where should this ajax call be made? Ideally it should be run as soon as possible, so should it be executed in the app.run()?
Second, where should this data that gets returned from the sharepoint server be stored? I read that making a factory for the sole purpose of storing data is not best practice, and it is better to just use the $rootscope. Right now, I am just storing a User object in a factory call "User" which in hindsight I guess is a no no
Finally, I'm not sure if there is a way to suspend the loading of the controllers as they are heavily dependent on this on the data that gets returned, but if there isn't, how would one communicate the information that gets received to the controllers. Would this be a case to use the $broadcast method?
Right now I have a kind of hackish solution. It gets the job done, but I'm pretty sure it is less than ideal
Here is a part of one controller. I am injecting the factory User into it
if (User.HasLoadedUserProps == false)
{
User.registerObserverCallback(hasLoadedProperties);
User.GetUser("1111");
}
else
{
if (User.IsAdmin == true)
//do whatever
}
Once the necessary information has been returned from the ajax call, it calls this
var hasLoadedProperties = function ()
{
if (User.IsAdmin == true)
//do whatever
else
utilities.popupBox("You do not have permission to view this page", "Access Denied");
}
Any wisdom, insight, or advice is appreciated!
First:
When your ajax call should happen depends on a few things, but since you mention that you'd like to defer controller loading until the user data is pulled down, your best bet is to put the call in your service. More on that in my response to your last item. Placing that data in a service also makes it easier to share across controllers, which brings us to the next point...
Second:
Your user data absolutely should go in a service, and absolutely should not go in $rootScope. Think of $rootScope like you do window / globals in JavaScript. You want to avoid using it for much of anything. An exception would be where you really, really need to use events ($broadcast/$emit/$on) but even those cases should be rare.
Finally:
Look into the resolve option for $routeProvider (there are similar options for ui-router if you prefer that route (no pun intended).
This option allows you to defer the instantiation of a controller until a set of promises is resolved. In your case, you should return a promise from your User service, which is resolved once the user data is retrieved.
To help demonstrate these points, I made this simple demo. This code, along with the links to the Angular docs, should be enough to get you going ...
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'beer.html',
controller: 'BeerController',
resolve: {
beer: function(Beer){ //injected into controller once promise is resolved
return Beer.getFavorite();
}
}
})
})
.controller('BeerController', function($scope, beer) { // Will load after 3s
$scope.favoriteBeer = beer; // beer comes from resolve in $routeProvider
})
.factory('Beer', function($timeout) {
var beer = {
favorite: 'porter'
};
beer.getFavorite = function() {
return $timeout(function() { // pretend this is an ajax call
return beer.favorite;
}, 3000);
}
return beer;
});
...where beer.html contains:
<div>
My favorite kind of beer is: {{favoriteBeer}}
</div>

How to change the same values everywhere - in service , controllers, outside angular?

service implementation
myService = function()
{
this.config = {
show0: false,
show1: true,
role : -1,
id : -1;
};
};
in controller, I map the config values
$scope.config = myService.config; //I guess this by reference, isnt it???
in templates of these controllers for e.g. the $scope.config.show0 is used with for e.g. ng-model
Now outside angular in my threejs code
I get the service using injector which I have defined earlier and change some values depending on certain conditions
var service = window.my.injector.get('myService');
service.config.id = 1991;
Now this value is not immediately reflected in the HTMl template,
Source = {{config.id}} still renders as Source = -1
But when I click on some other button in the same template which is mapped to any other value in the same scope
Source = {{config.id}} still renders as 1991
How should I force this rerendering or refreshing in my non angular code soon after
var service = window.my.injector.get('myService');
service.config.id = 1991;
///do something to refresh that controller
Am I using the service wrong? How should I make this config available in angular controllers, templates and non angular code if not via a service?
Shouldnt changing the $scope.config properties values and changing the values outside angular by retrieving the service via injector change the values everywhere ?
This is because the angular digest cycle does not kick in from your threejs code. I am not sure where your three js code is, but try using $scope.$apply to kick in the digest cycle, and it should work fine.
If you can share a jsFiddle, I can have a better understanding on what you are trying to achieve, but the reason why this is not happening is, as I said, that the digest cycle does not kick in.

Categories

Resources