angular 2.0 mandatory refresh like $apply - javascript

I am create an app to drag a component(angular2 component, same below) from a list and drop it into another component. In this process I used interactjs to drag and drop component. But when I drop it into another component, It only load the static html in the component template which dragged.
For example I have this component to be added into another
import {Component, View} from 'angular2/angular2'
#Component{
selector:"sample"
}
#View{
template:`<p>static content</p><p>{{contentToBind}}</p>`
}
class Sample{
contentToBind:string= "I am the binding content."
}
when it added, it should looks like below
static content
I am the binding content.
But actually it just display static content like
static content
You can check this example in this plunker.
And then I bind a click HostListener to this Sample component, when I click the component has been already added into another component, "I am binding content" will appear(other event triggered is same).
I think due to interact it has jumped out of angular2's lifecycle.
Any similar method as $apply() in angularJs 1.x?

Interact is not a part of angular 2, maybe your code in Interact is out of angular 2 scope as you said.
You can use NgZone in your Interactjs file in plunker, I edit your code and it's worked now. You should send your event inside of NgZone.
something like this.
myParent.ngZone.run(
() => {
console.log("onDrop...");
ce.drop("Hello");
}
);
See it on plunker
Plunker

Related

Angular template not rendering

Right now I am creating a library (my-custom-library) and a project in which we'll use that library (called my-Project)
The requirement is, that within my-project I have to use my-custom-library, extended with templates, like this (my-project's app.component.html):
<my-custom-library>
<ng-template #myTemplate>
<div>Some static content for now</div>
</ng-template>
</my-custom-library>
The reason for this is, that in my-custom-library they want to have template-able components, where the template is given from the outside (in this case from my-project).
Within my-custom-library I'm supposed to access the given template(s) and pass them to the corresponding components. This I'm trying to achieve (my-custom-project's app.component.ts)
#ContentChild("myTemplate") myTemplateRef?: TemplateRef<any>;
(my-custom-project's app.component.html)
<ng-container [ngTemplateOutlet]="myTemplateRef"></ng-container>
My problem is, that the contentChild is always empty, the template never renders. The structure itself I think is working, since when I'm moving this same structure within just one project and use it there everything works fine, the contentChild gets its value and "my template" is rendered.
One more information, I don't know if its useful but my-custom-library is created like this (my-custom-library's app.module.ts):
export class AppModule {
constructor(private injector: Injector) {
const customElement = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('my-custom-library', customElement);
}
}
What could cause this issue? Is it even possible to achieve this?
I had the same issue, Apparently ngTemplateOutlet does not work with angular elements. but you can try content projection without ngTemplateOutlet and it works fine.
e.g
<my-custom-library>
<div placeholder1></div>
</my-custom-library>
and you can define placeholder1 within your angular element (my-custom-library)
e.g
<div>
/*your angular my-custom-library code here */
/* the content you want to inject from outside of your angular elements*/
<ng-content select="[placeholder1]"></ng-content>
</div>
Note: you can also do nesting of your angular elements as well using this, but with this approach you have to make sure that ng-content is not affect by any ngif condition, because your angular element can project the content from outside but it can not regenerate projection based on your conditions. those conditions should be added from where you are projecting content.

Angular > How to use a content query to get an element inside an template outlet

In an Angular app, I've developed a reusable component whose responsibility to take care of rendering a wrapper around content provided by the parent component. The wrapper provides some layout and functionality that is required by multiple components (the parents). To accomplish this, I've adopted the "Component Composition" technique outlined in the following article which relies on the use of NgTemplateOutlet to enable the parent component to provide the content rendered inside the wrapper.
https://blog.bitsrc.io/component-reusability-techniques-with-angular-727a6c603ad2
This approach has been working well in a variety of situations but now I've come across a new situation where one of the parent components needs to use a content query to get an element inside the template outlet. I've been unsuccessful in using either the ViewChild or ContentChild decorators to get a handle on the element.
The following pseudo code outlines the basic approach I've attempted to take to date.
Reusable Element:
<div class="card">
<ng-container *ngTemplateOutlet="chart"></ng-container>
</div>
...
#ContentChild('chart', {static: false})
chart: TemplateRef<any>;
Parent Component:
<app-shared-component>
<ng-template #chart>
<div #top10Graph></div>
</ng-template>
</app-shared-component>
...
#ViewChild('top10Graph', { static: false }) private top10GraphContainer: ElementRef;
ngAfterViewInit(): void {
console.log(this.top10GraphContainer); // undefined
}
Is there any solution for using a content query for obtaining an element inside a template outlet such as I'm using here, or is another approach required?
The end goal (not demonstrated here) is to enable the parent component to render a data driven graph inside the template outlet.
I'm using Angular 10.
I think you get undefined because using ng-template is not yet rendered.
This code can work for you
<app-shared-component>
<ng-template #chart>
<div #top10Graph></div>
</ng-template>
<ng-container *ngTemplateOutlet="chart"></ng-container>
</app-shared-component>
Hope useful

injecting dynamic html inside the components from index.html in angular 8

I am working on a web app. which has magnolia as CMS. i am still new here but i will explain the scenario.
magnolia is providing the index.html which has reference of the components.But for some of those components it also provides some additional html content. this additional content has to be shown inside the particular component's template. refer following for better understanding.(remember this is inside the index.html)
<my-component>
<div> this division has to be shown inside the my component template.</div>
</my-component>
I have tried following approaches till now.
trying to use - this apparently does not work as i have learnt recently that the angular is not the master of root template(index.html). so ng-content never works. correct me if i am wrong.
using shadow dom view encapsulation. I am not expert in this, but setting viewencapsulation = shadowdom and defining slot inside the component template fulfills my purpose. The only issue with this approach is the scope of this shadow element. it will be inside the shadow root which has its own scope so no global styles are applied inside it. i had to import all the global css for each such component, which makes the main.js go crazy in size.
can someone please suggest me if there is any better or other solution to this problem?
Have you tried using Input() values for that component?
index.html
<my-comp [myInputs]="'My Input HTML <b>Content</b>'">
your receiving component…
<div [innerHTML]="myInputs"></div>
On my side, I use <ng-content></ng-content> inside the component where I want to put my dynamic content.
Ex:
<app-help-tool>
<span i18n="##pictoTable_helpPictoList">Click on a picto to see its description.</span>
</app-help-tool>
And in HelpToolComponent.ts:
<div
class="help_content"
*ngIf="this.isVisible && this.helpService.isHelpOn()"
[#showHideHelp]
(click)="showHideHelp()"
>
<ng-content></ng-content>
</div>
The result is to put the span content into the div of the component.

Angular 2 add custom component to Owl Carousel 2

I have created two components in Angular 2:
ReaderComponent: The one that initiates and controls all functionality to Owl Carousel (initiate, add slide, remove slide and so on)
PageComponent: Each slide is a PageComponent and has events to handle input from the user (click, pinch, doubletap)
The ReaderComponent is created at start of the application and initiates a request to a service to get all data for each of the PageComponents.
Everything works fine until we add a slide that is a PageComponent. I have tried to add the PageComponent selector to owl Carousel:
this.slider.trigger("add.owl.carousel", ["<my-page-component></my-page-component>"]);
This does add an element of <my-page-component> but does not render the template or handles any of the PageComponents events.
I have tried to add all the PageComponents to an array and render it in ReaderComponents template:
<div *ng-for="#page of pages">
<my-page></my-page>
</div>
This renders correct but by that time all pages is rendered Owl is already initiated and no pages is visible.
So to summarize all of this: I need to know how to add a custom component via javascript (in this case the add functionality of Owl)? Is this even possible? Or is there another way to handle this so that I can add PageComponent in any way?
The first method you mentioned would require you to force angular to re-check it's bindings. This is probably possible, but I don't know off the top of my head.
The second method is much easier. You can use the lifecycle events of the Page or Reader Components to trigger the adding. They are as follows:
export var LIFECYCLE_HOOKS_VALUES = [
LifecycleHooks.OnInit,
LifecycleHooks.OnDestroy,
LifecycleHooks.DoCheck,
LifecycleHooks.OnChanges,
LifecycleHooks.AfterContentInit,
LifecycleHooks.AfterContentChecked,
LifecycleHooks.AfterViewInit,
LifecycleHooks.AfterViewChecked
];
If you add a listener to your PageComponent class, you can probably use OnInit or AfterViewChecked and then get it to add it's own element reference to the carousel (basic example). From a quick look at their documentation, it doesn't look like owl supports adding a new element, so you could have the PageComponents all on your page somewhere hidden and then just add the raw html from the elementref, then remove it again in the OnDestroy function.
If you do it in ReaderComponent you should look at OnChanges or add some clever checks into the DoCheck function and then just get it to reload all items inside it (perhaps owl.reinit?). I've not used the owl carousel before so can't be more specific there I'm afraid.
These are exported from the angular class as interfaces, so you should be extending your classes from them. An example is available on the Angular 2 website here: https://angular.io/docs/ts/latest/api/lifecycle_hooks/AfterViewChecked-interface.html

Add ExtJS components at run time - "refresh view"?

I am adding components to a panel at runtime:
Ext.define("MyApp.view.SomePanel",{
extend:'Ext.panel.Panel',
...
setGridList:function(gridIds) {
myItems=[];
Ext.each(gridIds,function(gridId){ myItems.push(Ext.getCmp(gridId) || Ext.create("Ext.grid.Panel",{id:gridId}))});
Ext.applyIf(me,{items:myItems});
}
});
It works well when called for the first time, from the initComponent. But it does not work when called from a store load handler. My best guess is that I have to refresh the view, rebuild the layout or sth. like that!? But I don't find such a thing in the docs.
Anyone here knows the trick?
If your class MyApp.view.SomePanel is an Ext component, than you could use the Container.add() or Container.remove().
If the child is not automatically added, call the Container.doLayout() method.
PS: the layout of your class should support multiple children.

Categories