Let's say I have the main app.component with <router-outlet/> and this component can have multiple nested components. Some of them are very lightweight, some of them have tons of component-code + a lot of DOM objects, like images etc.
It looks that when I use on my main app.component
public ngAfterViewInit(): void {
console.log('loaded: ', new Date());
}
it fires imideatly after this component's view is inited, not taking into account all nested childs (I can't hardcode ngAfterViewInit everywhere - I have more than 100 components).
Is there any good way to know when all components Views are invited in Angular?
Also is there any good way to know also when all images are loaded on current route page?
When your root component is loaded this is signal about all child component is loaded on that CD tick. With router components, you need to implement the same logic(when the root of the current route is loaded then all children are loaded).
Example link with loaded images counter, router-outlet counter and how works ViewInit
I guess not all components are loaded when you initiate app.component.ts. it's more about modules, when you hit a lazy loaded module all of its components are initiated, and so on.
Related
I'm using Vue.js 2.x + Quasar 1.x with http-vue-loader (so no build tools) at the moment.
I put a q-dialog in a separate component - let's call it MyComponent, and when I just hook it up in a parent component like so:
<my-component></my-component>
then nothing happens, it's not even in the DOM... When I just insert the whole q-dialog template into the parent component, without having its separate external component, everything works just fine with a simple v-model.
So I imported the component successfully, that part is fine.
I was trying to invoke it when I click on a button, but I can't really communicate with the component this way.
Now I've come across two separate ways of creating dialogs in Quasar, the first one is using the component when it's not in its separate component. The second one seems to be the one I might need for a separate dialog component. The problem is that importing an external component with vue-http-loader looks like this:
components: {
'my-component': httpVueLoader('/components/MyComponent.vue'),
},
while according to the Quasar docs, it should look like this:
import CustomComponent from '..path.to.component..'
...
this.$q.dialog({
component: CustomComponent,
...
The docs are a bit confusing to me as well. :/
Unfortunately, I can't see the CustomComponent code, which is required to be created following an interface, which is described in this docpage under the warning. Make sure that CustomComponent is valid.
P.S. - Both of those ways do the same thing but in different ways. With the first one, you'll import that component to another and set him in the template, but with the second one, you'll call a tool, that creates a new modal with passed parameters. But the second one doesn't have all functionality compared to the first one.
Please check out this page and its source code. If I remove the cdn for the vue-tag-input component, everything except the component renders. But as soon as I add the cdn back, everything after first instance of tag-input component is not rendered on DOM. No error logs.
Please help me understand what is going on. As far as I understand there should not be any issue with component as I can render multiple instances and the same page layout in vue app using cdn. Check out App.vue file as well. This works perfectly fine.
You need to use valid html5 so you can't use self closing tags.
Change <tag-input v-model="tags" /> to <tag-input v-model="tags"></tag-input>
When vue component is used directly inside the html (not in single file vue component template), we need to take care of certain things
Don't use self closing tag for the component
convert all camel case to kebab case for component name and all the props (custom attributes)
There were above two errors because of which the implementation in question was not working.
My issue here is that I need to render separate route components to elements created by the backend. It's irregular I'm sure. Essentially I'm starting with an html document and need to render route components to particular elements in the dom.
Example:
If I have four components that each need to be rendered to a pre-generated element.
<body>
<div id="elone" />
<div id="eltwo" />
<div id="elthree" />
<div id="elfour" />
</body>
Now I need to render my respective components to each of those elements. The issue is that if I call ReactDOM.render within the component it doesn't recognize the router, and it doesn't appear that route has anyway to render to a particular element.
Note: I cannot unfortunately write the document within the JS, it has to be pre-generated. I don't need this to be done through react router if there are other solutions, but the components must recognize the router.
I hate answering my own questions, it makes it seem like no one is really answering questions here.
Anyhow the solution is to use ReactDOM.createPortal instead of ReactDOM.render within the components. Make sure to render the component with the router to an element outside of the container that you want to portal your subcomponents to otherwise you'll obviously clobber the elements that your portals are pointing to.
The page shows basic markup, comforting message and loading indicator.
<html>
...
<body app>
...page layout and loading stuff...
</body>
</html>
And root component is
#Component({
selector: 'body[app]',
template: `<ng-content></ng-content>`
})
App {}
A plunker that demonstrates the problem is here.
After SPA initialization it is supposed to bootstrap body element and compile components while saving existing basic layout.
However, root component just ignores ng-content.
This leads to two options. The initial layout should be dumped and shown only after bootstrapping. Or it should be duplicated in both root component template and HTML document (likely with server-side templating). None of them looks good enough.
body contains sensitive markup that cannot be just wrapped into child component to overcome this limitation. I intend to use Angular Universal to provide SPA with neat static preview, but not at this stage.
It looks like it is a known problem but I'm unable to find a workable solution.
How can it be fixed?
The link below has been given the status fixed by ivy. Ivy is a milestone for angular v7.0.
Transcludes are not supported on the root element, you can't pass anything to it because index.html isn't part of angular. If you can't embed the html within another component then I wouldn't expect it to work with ng-content either.
From https://github.com/angular/angular/issues/1858#issuecomment-207993202
Components only work as components when referenced in the template of
another component, yet they are expected to be used outside of this
which causes confusion
Using <ng-content> in root component planned to be implemented.
https://github.com/angular/angular/issues/4946
I’m currently building a little Ember App that allows users to access a newspaper’s travel tip articles through a map. Therefor I’ve build a little Leaflet component that displays a map the app can interact with (animate to coordinates, change zoom and stuff).
The map is the central element of the app and is always visible. So I placed the component into the application template. It fills the whole background and is positioned fixed. All child routes are rendered in div.content that “hovers” over the map.
…
<div class="app-body">
<script type="text/x-handlebars" data-template-name="application" id="application">
<div class="map-container">
{{leaflet-map
id="map"
class="map"}}
</div>
<div class="content">
{{outlet}}
</div>
</script>
</div>
…
As I have to preload all the articles with their coordinates right at the beginning (to place all markers), I added the preloading to the beforeModel hook of IndexRoute and fetch the data from store in the routes’ model hook via return this.store.all('article');.
The idea is that the map in the background loads right at the beginning and is already visible when the app starts to preload the articles. I thought that would be the case if it is placed into the application template directly. Obviously it’s not. The map is loaded and displayed after the preloading is completed and I don’t have a clue how to change that. Would be great if someone could hint me in the right direction.
Update
The console logs show that the compontent, despite it’s part of the application template, is initialized at the end after everything else. No idea why.
…
[✓] template:index ............................................. template at index
[ ] view:default ............................................... undefined.DefaultView
Transition #0: TRANSITION COMPLETE.
[ ] helper:leaflet-map ......................................... undefined.LeafletMapHelper
[ ] component-lookup:main ...................................... undefined.MainComponentLookup
[✓] template:components/leaflet-map ............................ template at components/leaflet-map
[✓] component:leaflet-map ...................................... undefined.LeafletMapComponent
The template (map) won't be rendered until the model resolves. The model won't be resolved if either hook beforeModel or afterModel return promises.
You placed the map in the application template and fetch articles from the index route, good. The problem is that nested routes, that return promises, block their parents too. The application transition is blocked until the index transition resolves.
So while you wait, you can use Loading / Error Substates . In this case, the loading state.
Example: http://emberjs.jsbin.com/sihedi/1/edit?html,js,output
With the loading state you allow a partial rendering and when the nested route completes its transition, the loading template is replaced with whatever your app does.
When you load your app, the first thing it's going to do is handle the App.ApplicationRoute. It will go through its model hooks, set up the controller, and render the template. After that, it will do the same for the App.IndexRoute (note: an index route is always implicitly created underneath parent routes), and render its template into the {{outlet}} you have defined above.
Thus, It seems to me that you should put the code that finds your markers into into App.IndexRoute.
You may still have an issue, however. If your {{leaflet-map}} component is something that must be loaded asynchronously (which seems to be the case looking at http://leafletjs.com/reference.html), the map itself won't appear instantly after the component is rendered in the DOM. In this case, you should listen for the event that says the map has been loaded, and then trigger an action that can be handled at the route layer to load the markers.