Upgrade Angular UI-Router to 1.0 breaks resolve inside views - javascript

I'm upgrading my applications Angular UI-Router to 1.0. The migration guide states
We no longer process resolve blocks that are declared inside a views
Fair enough. All resolve blocks should be put in the parent state however there is a limitation to this, which I'll explain.
My project currently uses named views and resolves data inside those views. This data gets passed to the controller. The issue that I'm having with upgrading to 1.0 is that some of my states re-use the same view and controller. The difference between the views is the data I pass to them via the views resolve block.
Here is an overly simplified example of what my application currently does
https://embed.plnkr.co/SFCzutU7N0AGsxpk9c6r/
As you can see, if was to move the resove block to the parent state, I would no longer be able to customise the data passed to each controller instance.
What is an alternative or workaround for this breaking change?

No answers :( Perhaps the question wasn't clear. Anyway, this is the solution I came up with. Not that happy with it but it works.
https://embed.plnkr.co/1YxFvHGjowYMvUhXmVsj/
I created a directive that I use on the ui-view element.
<div ui-view="blue-view" ui-view-param="blueView"></div>
This adds the given value to the parent scope.
I can then use this value to get the correct configuration.
$scope.color = viewParams[$scope.uiViewParam].color;

Related

After death of few Angular1 componets, The rest remain Same?

I am just curious to know, Is it like after the removal of few components like :
The rest off other components will remain same, because it is not mentioned in the image above
like:
Services,
Event (broadcast, emit, on)
run block
constant
config
And many others.
Hope the above question is valid, If so please give me idea about what is still remains , so that I feel easier in learning/adapting the new angular 2.
TypeScript:
I have seen the changes in class oriented block changes in typescript
like :
class MyComponent {
constructor() {
this.name = 'Max'
}
sayMyName() {
console.log('My name is', this.name)
}
}
Does that mean the commonly used DOM manipulation functions like
document.getElementBy
window object
And other things will same to an extent ?
Please give me some reference or idea about How much the Typescript has changed
Question 1:
The high-level abstraction is still the same (controllers, directives, services), but all the implementation details changed as the framework is rewritten in TypeScript.
For example, angular modules will be ditched in favour of ES6 native ones, which means run block, constant and config will not be relevant. Howevver, since they're keeping dependency injection, some way of configuration must exist, so whatever you can do in config and run will still be doable.
Question 2:
You probably confused TypeScript with JavaScript. The former has always had a syntax like that (so will the next version of JavaScript (ES6/harmony) to some extent).
However, the language change does not affect how you use the framework as TypeScript is supposed to be a superset of JavaScript, so most valid JS is also valid TS. You do not have to use features specific to TypeScript if you don't want to.
Based upon my understandings of how angular 2 is coming together this is how I see the other pieces fitting together.
Disclaimers
I am not a developer on the project, just a guy who is trying to keep up with the project as it is being developed.
The current state of angular 2 is alpha/developer preview and can/will change as development progresses
Overview
As angular 1.* progressed in its maturity there was a clear movement to utilizing conventional JavaScript patterns (see controllerAs, bindToController, no global controllers) and by following that convention your code for angular 1.* will be closer aligned to angular 2. The other movement that will assist you as you prepare for angular 2 is to think about your application in the idea of components (directive + controller with services injected in).
Services
These are classes that can be injected into components
Events (broadcast/emit)
These are a pub/sub implementation based upon the inherited $scope model which is not going to be present in angular 2, so another eventing model will need implemented. I have not heard this discussed from the angular team, so either be patient or pick another pub/sub model to implement.
Run block
With angular 2 being component based when the app is run is a direct correlation with the constructor of the root component (the one being bootstrapped)
Constants
Constants in angular 1 are just values that can be injected into other components, nothing has changed here and values can be injected into components in angular 2.
Config
With the angular module system going away in lieu of ES6 modules the idea of configuration (initializing values for a service) can be done in the constructor of the service. Also, angular 2 is going to support the idea of lazy loading additional components so configuration can be done later as well as upon application start
references
angular 2 project home page https://angular.io/
ng-conf videos https://www.youtube.com/user/ngconfvideos
angular 2 todo demo https://www.youtube.com/watch?v=uD6Okha_Yj0
angular 2 forms intro https://www.youtube.com/watch?v=4C4bmDOV5hk
getting started video https://www.youtube.com/watch?v=HmWm21cCAXM

Angular - Lazy loading an entire page from CMS

I'm attempting to build an angular app that is driven by the CaaS/CMS known as Prismic.io.
Phase one of this project will be a straight forward content-silo (CMS-managed), and phase two will add on more complex web app components. Knowing this, I've decided that Angular would be my best bet, but I'm struggling to think of a good solution to have all of the content lazy-loaded from the Prismic API.
One solution I've decided to explore would be to have a standardized $scope variable, let's call it $scope.loaded. Each controller will do what it must to query my Prismic service for its respective content, and once it's completed, it would set $scope.loaded = true.
The part I'm stuck on with this approach is how exactly to display the page while all of these components are loading. The easiest way would be to include ng-if directives that reference this loaded value, but I feel like there'd be a massive flash of unstyled content. And yes I could use spinners, but the idea of having 90% of the page covered in spinners seems chintzy.
Then I got to wondering: what if I pull up a loading screen for the app until all controllers' $scope.loaded values are truthy? In that case, how would I know which controllers are currently active on the page and reference their respective scopes?
(If you have comments about why this approach is bad, I'd love to hear them as replies rather than answers. I imagine this could create too many http request, for example).
A couple of options here:
Have you looked at ngCloak to see if will help you here with the flicker problem? https://docs.angularjs.org/api/ng/directive/ngCloak.
If you're using jquery, you could have a global spinner that works on concurrent ajax requests http://api.jquery.com/category/ajax/global-ajax-event-handlers/.
Or have a look at something like this global angular spinner https://github.com/monterail/angular-global-spinner/tree/master/src.
If none of these work, you could always create an array on the root scope where each controller/directive registers itself and sets its loading flag. Then add a watch to that variable to see when all components in that array are finished loading.

Is it possible to retrieve the controller of a directive compiled inside another directive?

I'm stuck on structuring components inside a large AngularJS application I've been maintaining and I'd really love some guidance since I'm at my wits end. Please bear with me!
Context:
I've got some directives that I'd like to have communicating with each other. As such, I thought it was appropriate to define a controller in each directive to expose an API for other directives to make use of. Now, I'm well aware of the require property in directives and how one can pull in the controllers of parent directives to use. Unfortunately, in my current circumstances, I have directives that don't necessary fit the use of requiring controllers.
Instead of using require, the code base I'm faced with has mostly chosen to add directives directly to the DOM and then to compile them afterwards. I suppose this was to allow for flexibility on customising how directives depend on each other.
I've included a snippet from the link function out of the demonstration Plunker further below that I created to help visualise the problem I'm facing. Note how directives are being attached to the DOM and then being compiled. I tried as best as I could to create a simplified version of the code I'm actually working on because I can't post it.
link: function(scope, elem) {
scope.data = '...';
var d2Elem = elem.find('li').eq(0);
d2Elem.attr('d2', '');
var input = angular.element('<input type="text" ng-model="data">');
elem.find('li').eq(-1).append(input);
$compile(d2Elem)(scope);
$compile(input)(scope);
// Able to get d1 directive controller
console.log(elem.controller('d1'));
// Not able to get compiled d2 directive controller
console.log(d2Elem.controller('d2'));
// Able to get compiled ng-model directive controller
console.log(input.controller('ngModel'));
}
Question:
Could somebody please explain why I'm seeing the behaviour I commented on in my Plunker? Why is it that when I compile a directive I've defined (i.e. d2), I cannot access it's corresponding controller even though it exists in the directive definition?
Coincidentally, I found that after compiling the built-in ng-model directive, I can in fact get its controller.
An extra point I'm pondering: Is the process I've described the least painful way to go about managing directives that communicate with each other? Noting that these directives don't necessary have strict parent-child relationships.
PLUNKER
Would very much appreciate some thoughts!
It is taking time until d2.html is being loaded asynchronously by Ajax, until it's loaded completely you cannot access it's controller, see attached screenshot, after ajax call it's able to access controller of d2.
I tried by replacing
console.log(d2Elem.controller('d2'))}
with
setTimeout(function(){console.log(d2Elem.controller('d2'))},1000);
And it worked for me, may be this will give you some hint or may be putting delay will resolve your issue, I know this is not good practice!!

Initialize Angular $scope on initial load

I would like to init the user session with some data. On loading the main outer controller (I have a "global" controller that is run for the entire app and individual controllers for each state/route) I currently check if the local session data is empty and, if so, fetch from server and return a promise.
The issue that I have is that I use directives which need this session data. Currently they run before the scope is populated. I need a solution that does not involve modifying all the directives to use promises/callbacks/etc.
On researching this I found many requests but no viable solutions. I am using UI router and looked at the grandfather state idea but that just seems to act as a master resolve that still needs to be addressed in each controller.
I have also looked at manually bootstrapping but I need to populate the scope and I don't see how to do that from angular.element.
I should add that this needs to a pause the Angular process until loading. I see suggestions for global configuration but not sure how do pause besides deferring bootstrapping.
Suggestions?
Can you do your work in main module's .run method. and set whatever you want at $rootScope.
That way it will be visible everywhere.
Angular Modules
You can use value receipe, ngtutorial.com/learn/value
You can write your provider which will perform you some functionality.
You can take a look here - Documentation for providers how to do it. From the link you can see:
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts.
By the way, if you want to access scope from angular.element = you can use:
angular.element(<yourElement>).scope()

Deferring angular controllers until Ajax call is completed

First of all, I have googled and searched on SO for this question. None of the answers I've seen are really satisfactory for me. I am aware of resolve & manually bootstrapping angular and neither are great solutions for us.
Essentially our app is constructed such that at the top level, we have a
<body ng-controller="applicationController">
that instantiates a bunch of stuff. Part of that is getting some data from our server and setting it so that children controllers have access to it. So the issue is sometimes the children controllers are executed before the server has responded.
We use angular UI's ui-router so we can take advantage of states. However resolve hasn't been a great solution for us because we have a bunch of routes and a user can enter the app from any of them. So far my only solutions are to create a very high level parent state and putting a resolve on that, or putting a resolve a multitude of states. Is there a way to make the ajax call before the angular controllers are run?
I upvoted both answers here because, in my opinion, the most elegant solution is a combination of both (without redirecting back and forth). The core of this problem is the fact that angular only allows synchronised dependency injection on controller arguments via the route provider. We can however wrap all our initialisation in a single service and let our main controller to be dependent on this.
See this plunker for a live demo.
What about ng-include (http://docs.angularjs.org/api/ng.directive:ngInclude)? Remove all the subcontroller stuff from your html file and put it in a template file. Now you may load some data from your server and if they all have arrived set the ng-include src.
With this solution you also have the possibility showing another template file during the loading phase.
If you don't want your content in another file you may consider writing a directive that can handle inline templates:
<script type="text/ng-template" id="my-awesome-content.html">
...
</script>
If you want to delay the instantiation of your controller, you need at some point to take advantage of promises and $routeProvider.
Misko Hevery (the creator of AngularJS) answered such question here: Delaying AngularJS route change until model loaded to prevent flicker
He updated the "AngularJS getting started tutorial" to conform to that pattern; it is worth reading it.
I run into the same question a few months ago; I architected my app to follow that principle.
Basically set a url/entry point in your app that resolves the instantiation of your controllers.
If your app is accessible from other locations, redirect the call to that entry point/url; after the init stuff has been resolved, redirect to the requested url.

Categories

Resources