Angular + Knockout issue with multiple bindings - javascript

I want to start by saying that this is something I have to live with and I didn't made any decision on this.
We have an Angular Application in which we implement a Knockout component.
We apply the bindings to the component in the angular controller after all promises are resolved.
As it is a single page application if we go to another page and try to get back to the page with the knockout component we are getting the error:
you cannot apply bindings multiple times to the same element.
This is manily because the first time we loaded the page all the bindings were applied.
We tried using the ko.cleanNode() but it doesn't work. I think because it is a componend and not a ko element.
I am wondering if the right approach is to recreate the knockout component or force a reload of the angular module (which I know works b/c if we hit refresh on the browser the bindings work just fine).

Related

Force a directive to always load prior to a controller

I am working on a UI issue. There is a misfire in load order that happens 1 out of every 50 times or so. The Angular JS app has a shared directive as a navigation button panel and that part is used by most of the other controllers.
Normal firing order
ButtonController.init() <--Set all buttons to hidden
EditGroupController.init() <--Set all buttons based on service call data
When the problem happens firing order
EditGroupController.init() <--Set all buttons based on service call data
ButtonController.init() <--Set all buttons to hidden
In scenario 2 above the EditGroupController tries to invoke an event on the ButtonController via:
$rootScope.$broadcast('setHeadersButtons', buttons);
However, when I trace into the angular internal code there is a logic branch where it looks for a registered listener with that name and it does not find one to fire because the module has not been loaded.
I remember in an Angular 7 app I used the APP_INITIALIZER to force a core piece to load first. Sorry if my wording is not precise front end / angular is not my specialty and this somewhat fell into my lap. Is there a way to ensure a directive in Angular JS is loaded before any other pieces?
There is an app.route.js, can I force the directive to load there?

How to preload an angular route and switch only when the route has been successfully loaded?

I am currently developing an administrative dashboard for my place of work using the BlurAdmin template. While this template contains many great features and great functionality, I found that this dashboard was not quite optimized for my use case. The dashboard that I am developing is completely based on a RESTful API built separately by one of my colleagues. Every page loads in its data through this API using AJAX and have found that most of the time, the page shows up before the API completes. This means that things just sporadically show up as the calls complete. In order to make for a smoother UI experience, I have began working on a solution for this.
Current Solution
While a route is being loading, a rootScope variable $isLoading is set to true which displays a loading overlay stretched over the page. In order to determine completion, I watch $http.pendingRequests.length until it is equal to 0 which tells me that the page has loaded successfully (based solely on http calls).
Desired Solution
While a route is being loaded, I would like the page not to change but instead utilize a top-bar loader and only when the page is loaded, should the routes change.
The routing is currently done by BlurAdmin using the ui-router module and the view is always instantly displayed by the ui-view directive.
My question then is: How do I preload an angular route into a hidden view while it builds, and only once I detect that all API calls have completed on this new route, should the hidden view switch to the visible view and the old visible view be removed?
You could do this by using a resolve on your state declaration. The basic idea would be to call your API from your resolve functions on the relevant state declarations. If you return promises from these functions the state will not be entered until the promises are all resolved. The values will then be bound into your component.
To show the spinner/loading bar on state transitions you could register a Transition Hook for 2 events: onStart and onFinish. Inside your onStart hook set some state on a service. Let's say isTransitioning = true;. Inside your onFinish hook, set this to false. Your spinner component could then watch this state and show itself when appropriate.

equivalent to ngAfterViewInit but general for all views

When views DOM is heavy, sometimes it gets some time to render it, especially on older mobile devices. I would like to put a spinner whenever the view is not rendered yet.
I can achieve that using ngAfterViewInit hook but doing it for every view provides a lot of duplicated code.
I was wondering if there is a global hook that is fired whenever rendering of current view is done.
As Jota mentioned in a comment, what you're asking for doesn't exist in angular. Something you could do, which may or may not be appropriate to your situation, is add a single spinner component to the root of your app (say, in app.component.ts) and create a service which can turn it on or off. This way, in each of your child components you could turn the spinner on in ngOnInit and turn it off in ngAfterViewInit.
Another option, if you're using the Angular Router, is to have this spinner component listen for router events: turning on at NavigationStart and turning off at NavigationEnd.

KnockoutJs v2.3.0 : "cannot apply bindings multiple times to the same element"

Problem:
In an existing application, I'm adding a new feature which uses knockout to display a grid and some additional information. I load some of the data at the start and prepare subscriptions which load other data using ajax, create viewmodel in Razor view to inject server-side variables, and then bind it (it does not matter if I pass html node or not, I have same problem).
Upon page load, "cannot apply bindings multiple times to the same element" error appears in console, and all of the html elements which use if, with or template bindings are empty.
The only occurrences of "applyBindings" in entire project are in my view, and in knockout source. Debugging shows that it is called twice, both times from $(document).ready
When I remove apply bindings from code, and call it later manually using console, it works.
Answer is already on SO: jQuery $(document).ready () fires twice
Theme of the application was moving/manipulating html elements, and tag with viewmodel initialization was inside same html view which was manipulated later. Moving to separate section which is rendered in head solved problem.

How to disable/enable controllers in JMVC?

Imagine you have one page app using Javascript MVC, which should switch between sub-apps and still stay on the same page. You can load additional controllers and views into the page, but to avoid the conflicts between different controllers, you need to enable the current controller and disable others. You can even destroy the controller and add the current sub-app controllers if needed.
Is it possible? if so, how?
Thanks.
Usually you have some kind of hierarchy on your page (e.g. a page controller, some for navigation etc.) and you only replace the controllers of the part of your page that actually changes.
For a central content element that means either destroying the controllers (by calling destroy on it) or replacing the element that will change (which will remove the controller attached to it as well). So you don't really need to disable anything because you are actually removing the whole thing.

Categories

Resources