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.
Related
My situation is that I have multiple SVG templates that have data binding on my Angular project, and I want to somehow be able to determine if the data that is going to be bound to these areas is going to fit or not (not get cut off/cover something else basically),somehow mark the products(the data coming in from the angular service) to symbolizes which template it best fits into, or even write/modify the template on an individual product basis and save a copy for each product that I could have the component reference instead.
I am partly able to do this with some basic jquery within the component checking the natural width and height of objects coming into the templates, but it REALLY slows down page load, so it's not viable
I came to the conclusion that I should use a custom webpack to do this, possibly write a loader that analyzes the data coming in from the angular service and figure out which template that specific product fits best. The loader could do the calculations to figure out what fits where.
The reason I want to do this in the webpack is because I ultimately need to do the calculations anyway, and it would really bog down the load time to try and do this much logic dynamically on user load, not to mention it's just redundant in my situation to figure this out more than once, as the product info will not change until the website is updated with a new API call anyway.
I currently have a property hard coded that indicates which template to use(a number corresponding to a template), but doing it this way limits the scope of possible templates, and opens up many possible programmer goofs, as well as the fact that it doesn't cover smaller issues that ARE noticeable, and becoming a problem.
So, my question has three parts:
Is it possible to call an Angular Service/API call in general within a loader.js/ts file?
Can I manipulate the data coming in from an Angular Service/API call and have it preserve those changes (changing a flag property of each product coming in from the service)? The interface in angular that handles the data coming in has an extra property that I could assign potentially in the webpack to denote which template to use.
Could I write html files to a folder on the local project/to a database using that data from a service and the base templates?
I apologize for the wordiness, but the situation has a lot of unique parts that I feel are necessary to include. I don't need code examples so much as I just need to know if Webpack/Loaders can/should even do this. I'm obviously open to any suggestions as well as to other ways to solve this problem.
Notes:
All the code I really have so far for the webpack would be configuring my angular.json to run off of a custom-webpack.config.js file I created, it doesn't currently do anything.
The service executes an http request and is subscribed to by angular components that consume it's data, but I could possibly write a js promise and recreate the interface for the scope of the webpack/loader, which is why I think it may be possible.
I'm new to angularJS and web in general so I'm interested if it's possible to display page after it's controller's $scope variables are initialized?
The thing is most of my $scope variables are used to manage dynamic look of a page. It comes to page is loading right on my eyes, and I realize things loading are my $scope things.
Is it possible to let controller load and calculate everything before it displays it on the screen?
Not really... because part of Angular's philosophy is to do everything possible from the DOM, and the browser is going to see some of those before any Javascript gets executed at all.
However, Angular DOES have a standard trick to work around this. Please review the documentation for ngCloak:
https://docs.angularjs.org/api/ng/directive/ngCloak
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.
When I start my application, my computer loads it 15 seconds. It loads a whole bunch of grids and things that I want to load dynamically.
What do I have to do if I want for those grids to be loaded "on demand"? Do I have to load controllers dynamically or just the grids? And how?
Thank you. :)
That depends on your application structure and the configuration of the stores. Following are some tweaks that you may apply:
remove autoLoad from the stores and keep in mind that you now need to care about loading if you don't apply paging or filtering. Why? Any store that you place in your controller store array will be instantiated as soon as the controller get instantiated, which is great but cause the load of the store if autoLoad is true. Based on the implementation the store will get loaded again for example a pagingToolbar will defiantly again fire a load so the first could be spared.
apply a sort of lazy controller loading. Meaning; only apply that controllers into the application controller array that you need right at the start. Load any other controller only when you need it by calling this.application.getController('ControllerName') within a controller or directly on the application controller. This will give you the conrtoller instance and init the controller (this is quite new, so I dunno since when this happens automatically. I check 4.1.3). Anyway, the lazy controller initialization will defer all Ext.Loader request for each of these controllers till the controller get initialized, so this will help you most I guess.
It looks to me as if those scripts are being loaded by the ExtJS loader itself, I'd imagine it's loading what it thinks it needs due to the structure of the page based on the settings provided.
Have a read over the loader docs to get a feel for what it's doing and why:
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.Loader
I know this is a very commonly discussed topic but I can't find anything that answers my question exactly :)
I'm working on a Backbone.js project at the moment. Router wise I don't instantiate views, models or collections within the router but instead just use the router as one way of dealing with state - the router calls methods on my custom controller object.
My controller then instantiates the different views, models and collections for index, show etc. This is all fine and dandy.
I'm just having a bit of a struggle with how to deal with page transitions. I've read all of the great posts on managing zombies etc, and know that whatever happens I have to have some cleanup system for old views (I'm currently using the .close() method that Derick Bailey blogged about).
If I'm going from #show to #index, or any other route change, I understand that it makes sense to just instantiate new, fresh views, models, etc - which is what I see in pretty much every tutorial. Making sure to cleanup old ones, of course.
But, if I'm already on #show say, and I route to another #show page, all of the views etc that I want are already instantiated and rendered. All I want to change is the data of the models and collections.
So I guess my question is why do I not see people re-using views very much. In my head I was thinking if you're already on the page that you want, it would make more sense to just update the url or urlRoot of the model / collection that that view is linked to and re-fetch. This would then trigger a reset event, and all views that need to can subscribe to this and re-render themselves.
But, as I say, I don't see people doing this. Is it just because it's a really bad idea? If someone is doing something like this, how do you deal with tracking 'refreshable' models and collections?
Thanks!
I think it depends a lot on how you are using your views and how complicated/large they are.
If your views are very simple then it is often just easier to rerender the entire view and replace the existing HTML with the new markup (it might also be faster then traversing the DOM to change the necessary parts. However if you have a more complicated view and there is only a small amount of information changing it is most likely better to listen to the appropate attributes change events (eg. _bind('change:name', this.nameChanged,this)) and then only update that part of the DOM.
Keep in mind that while the convention is to use a render method which renders the element, you can just as easily apply an additional refresh event to only refresh certain parts, you can then just swap models (like #jackwanders suggested) and call the refresh method.