How to select content from inner children in ng-content - javascript

I have a component called tab which has <ng-content select="[tabItem]"></ng-content>
Sometimes tabItem is inside other child components. My problem is Angular selects the content from direct children, not inner children (app-my-tab), is there any way to do it?
app.component.html
<app-tabs>
<div tabItem>
Tab 1
</div>
<div tabItem>
Tab 2
</div>
<app-my-tab></app-my-tab>
</app-tabs>
my-tab.component.html
<div tabItem>
My Tab
</div>
<div>
Other content
</div>
See this stackblitz

There is no solution for deep selection.
I thing it is logical, because:
understand and real code easily
easy to debug.
If you want really do that use *ngIf in app-my-tab.
To use *ngIF:
All element in app-tabs must have tabItem attribute
send your condition to show/hide some other element in to app-my-tab component. and app-my-tab receive it as #Input() property
in app-my-tab html use *ngIf to show or hide some element
Example: https://stackblitz.com/edit/deep-ng-content-2gyttv?file=src/app/app.component.html

Related

Angular: render numerous components on (click)

I do not want to render a new component or go to a new route, this is not my intention. I cannot use a single variable with an *ngIf to handle rendering the component as I cannot predict the amount of variables I will need to render.
Here is the situation.
<div ngFor="let stuff of lotsOfStuff">
<div (click)="generateAnotherComponent()">
<span>some basic info</span>
<my-child-component></my-child-component> //component to render on click
</div>
<div (click)="generateAnotherComponent()">
<span>some basic info</span>
<my-child-component></my-child-component> //component to render on click
</div>
</div>
You can generate the component dynamically.
There are various ways to achieve this, but one would be to use a template variable placed on an element, for example
<div #ChildInsertionPoint></div>
And then targeting this "insertion point" as where you'll place the newly generated components by using ViewContainerRef:
#ViewChild('ChildInsertionPoint', { read: ViewContainerRef })
childInsertionPoint: ViewContainerRef;
generateAnotherComponent() {
this.childInsertionPoint.createComponent(ChildComponent);
}
Dynamic component generation became a lot easier with Angular 13 (that's what I've assumed you're using). But if not
Finally, I'm assuming that you will bind your click event to a button instead of the div element itself.
Here's a small example on Stackblitz

How to render a content inside directive at various places

I want a component directive to render anything put inside it's selector to be rendered at specific sections inside its html.
header, footer, main in this case.
any.html
<any-selector>
<div>content to place</div>
</any-selector>
Expecting it to render following
any-selector.html
<header><div>content to place</div></header>
<main><div>content to place</div></main>
<footer><div>content to place</div></footer>
tried it with ng-content but it rendered only at first occurrence of <ng-content>
If there's any way to achieve this?
So, this is an expected behavior from ng-content, either you put [select] to point to certain ng-content or you can render just on the first occurrence of ng-content.
I tried a way which has worked for me. Here is the demo working code
<any-selector>
<div #myProjection>content to place</div>
</any-selector>
and then in app-selector.HTML you can do :
<div id='border'>
<h1>Hello Component</h1>
<header><div #canvas></div></header>
<footer><div #canvas></div></footer>
</div>
app-selector.component
#ViewChildren("canvas") canvas: QueryList<ElementRef>;
#ContentChild("myProjection") str : ElementRef;
ngAfterViewInit() {
this.canvas.forEach((div: ElementRef) =>
div.nativeElement.insertAdjacentHTML('beforeend', this.str.nativeElement.innerHTML));
}

angular4:ng-content nested class based selection

As we all know in Angular4 we have support for ng-content.
In this, we can select based upon class, element-name, attributes.
I am trying to select element based upon class :
Here is my consumer component html :
<my-component>
<div class = "item">
<div class = "item-small">small-item content</div>
<div class = "item-large">large-item content</div>
</div>
</my-component>
Now in my my-component template, I am trying to access div with class item-small.
My my-component template looks as follows:
<div class="my-component">
<ng-content select = ".item>.item-small"></ng-content>
</div>
But it is not returning me anything.
Here is the plunk for this issue:
https://plnkr.co/edit/2hlL2GezNXRoLCD1FAPD?p=preview
What is the best option to handle such cases?
Kindly give right approach to solve this problem.
I'm pretty sure only selectors are supported that directly match elements
This should work
".item-small"
but this not
".item>.item-small"
like with element or directive selectors.

Angular 1.5 nesting components

I have a container component that has 2 other controllers nested in it. I have them set up like so
container -> component1 and container -> component2
My train of thought here was that I could transclude the HTML from my page into my container component.
<container> <component1></component1> <component2></component2></container>
and then in the container HTML <div ng-init="vm.init()" ng-transclude></div>
Problem is, my container isn't running at all, I added a console log to its init function and no code is running. While component1 and component2 run their init's.
Seems to be a large amount of documentation covering older angular versions. Which tell me that they need to be nested like so <div ng-controller="parentController"> <div ng-controller="childController"></div> </div
How do you nest components into each other in 1.5?
Looks like the issue was that I was attempting to put a ng-init and ng-transclude in the same element. My guess is that ng-transclude overrides everything in the element it is on.
so I moved the ng-init to another element and its working fine
<div ng-transclude ng-init="vm.init()"></div>
changed to
<div ng-init="vm.init()"> <section ng-transclude ></section> </div>

How to expand DIVs the "angular way" (using angular masonry)

I'm trying to expand a DIV element on my angular layout. I'm using angular-masonry to give a mason-style to my layout, but now I need to expand those boxes on click. I've tried a lot of stuff, but it kept overlapping my others elements. Soon figured out that I'll have to write it the "angular way" so I don't run into DOM manipulation conflicts.
Here's my code:
<div class="row" masonry>
<div
class="masonry-brick item-component col-sm-4 col-md-4"
ng-repeat="component in components.components | filter : components.filterByFilter | filter : searchText"
ng-click=" // expand #expandable // "
>
<div class="component-wrapper">
<div class="component">
<img ng-src="#{{ component.thumb }}"/>
</div>
<div class="component">
#{{ component.name_en }}
</div>
</div>
<div id="expandable" class="expand-me codes-wrapper">
<p>XXX</p>
<p>YYY</p>
<p>ZZZ</p>
</div>
</div>
</div>
Here's what I want to accomplish in the "angular way": http://codepen.io/desandro/pen/daKBo
In your example (http://codepen.io/desandro/pen/daKBo) if you click on an element there are two things that will be done:
(1) the style of the clicked item is changed
(2) the function masonry is called on the container element that keeps the divs.
I can't see such a function in angular-masonry pre builded. So i'll guess you have to do this by your self. Here are some hints how to solve this (i havn't try it in real)
Bind a function to ng-click. In this function set a state to the current component. This state shoud be used to toggle the css-class of the element. you can use ng-class for this.
The second part is little bit more complex. I would suggest write a direcive 'masonry-change-listener' and bind it to the element that is bound to the same element with the directive masonry. If you click on a component $emit an event, that something has changed. In the directive 'masonry-change-listener' listen to this event. if this event fires you have to call $element.masonry.apply($element) in the link function.

Categories