Change content of router-outlet from inside - html

I have such a html in my app.component.html:
<login-menu></login-menu>
<top-menu-bar></top-menu-bar>
<div class="grid-container">
<router-outlet></router-outlet>
</div>
As you can see it is simple. Top menu bar injects components into router-outlet. How can I make that injected component could change this router-outlet tag content? Let say I want make that injected component have something like this:
<a (click)="showPersonalProfile('1')" >{{person.name}}</a>
and on click parent component router outlet was changed. I tried to do it by EventEmitter but I failed. Do anyone have any example how to solve it?

router-outlet is a placeholder, to show any component which matches a particular route defined in the routing-module.
By changing the route, we can control which component's app-selector gets substituted in-place of router-outlet.
So, to answer the question How can I make that injected component could change this router-outlet tag content? , we can do so, by navigating to that particular component using router.navigate(['path'] inside the showPersonalProfile() method.

In the function call the router navigate and set the primary path to the url you want as below
router.navigate([{outlets: {primary: 'path'}}]);

Related

How to set tabindex on library react components?

I have a React component that contains some third-party <Button/> elements, and I want to rearrange the tab-ordering, but it doesn't look like the component accepts a tabIndex prop. I have something like this:
import {Button} from 'thirdpartylibrary';
import TextPanel from './TextPanel.js';
const Component = ()=>{
...
return (<>
<TextPanel tabIndex={1}/>
<div className="buttons-wrapper">
<Button tabIndex={2}>Btn1</Button>
<Button tabIndex={3}>Btn2</Button>
</div>
</>);
}
Basically, I want <TextPanel/> to get focus first and then the <Button/>, but the focus always starts from the <Button/> first. The browser inspector shows that the rendered HTML buttons don't pick up the tabindexes I assigned their "corresponding" react components. For what it's worth, I checked the <Button/> component's source code and it looks like it eventually inherits from a ElementAttributes<HTMLButtonElement> - does this mean that there's some way of assigning normal html props to it?

How focus paritcular html component in page with Angular?

I want to scroll down to page. When I clicked anchor , I want to stay on same page but focus on partivular element or page down. How can I achieve this?
Create an element reference in your component like this
#ViewChild('whatever') myElement: ElementRef;
Bind it to the html element like this
<input #whatever />
Then you should be able to call focus to it like this.
function focusWhatever() {
this.myElement.nativeElement.focus();
}
Element References are a powerful tool in Angular for accessing DOM elements directly, particularly for stuff like this. Read more about them here.
Read more about the el.focus() DOM API method here.

AEM - CRXDE: cq:Dialog not showing for component

Starting out with AEM by using CRXDE, and making a structure component for a header hero component that will show a title and subtitle.
I wanted to add a cq:dialog by just copying the libs/wcm/foundation/components/title/cq:dialog component, and pasting it inside the hero component. There are two values: jcr:title and jcr:subtitle. When it comes to those values, they do display if I manually add them to my page from the contents directory.
The problem that I am facing is that the dialog is not showing at all when I hover over the hero area of the website from the editor.html view.
Is there something I am doing wrong?
Do not use jcr:subtitle. This property name appears to be outdated/invalid and will most likely throw an exception related to the node type definition. Simply use subtitle and you should be fine.

Angular4 ng-content gets built when ngIf is false

I have a problem with the new ng-content transclusion.
Let's say I have a component my-component that, in its ngOnInit() function does some heavy operation on load (for now, just a console.log()).
I have a wrapper, that displays the content via transclusion (my-wrapper.component.html).
<ng-content></ng-content>
If I set the surroundings up like this, the log statement doesn't show:
<my-wrapper *ngIf="false">
<my-component></my-component>
</my-wrapper>
I assume, the my-wrapper component does not get built, so the content is ignored.
But if I try to move the logic into the my-wrapper component like this (my-wrapper.component.html):
<ng-container *ngIf="false">
<ng-content></ng-content>
</ng-container>
I always see the console.log() output. I guess, the my-component gets built and then stored away until the *ngIf becomes true inside my-wrapper.
The intention was to build a generic "list-item + detail" component. Say I have a list of N overview-elements (my-wrapper), that get rendered in a *ngFor loop. Every of those elements has its own detail component (my-component) that is supposed to load its own data, once I decide to show more infos to a specific item.
overview.html:
<ng-container *ngFor="let item of items">
<my-wrapper>
<my-component id="item.id"></my-component>
</my-wrapper>
</ng-container>
my-wrapper.component.html:
<div (click)="toggleDetail()">Click for more</div>
<div *ngIf="showDetail">
<ng-content></ng-content>
</div>
Is there a way to tell Angular, to ignore the transcluded content until it is necessary to be added to the page? Analogously to how it was in AngularJS.
Based on the comment of #nsinreal I found an answer. I find it to be a bit abstruse, so I'm trying to post it here:
The answer is to work with ng-template and *ngTemplateOutlet.
In the my-wrapper component, set up the template like this (my-wrapper.component.html):
<div (click)="toggleDetail()">Click for more</div>
<div *ngIf="showDetail" [hidden]="!isInitialized">
<ng-container *ngTemplateOutlet="detailRef"></ng-container>
</div>
Note, that the [hidden] there is not really necessary, it hides the "raw" template of the child until it decides it is done loading. Just make sure, not to put it in a *ngIf, otherwise the *ngTemplateOutlet will never get triggered, leading to nothing happening at all.
To set the detailRef, put this in the component code (my-wrapper.component.ts):
import { ContentChild, TemplateRef } from '#angular/core';
#Component({ ... })
export class MyWrapperComponent {
#ContentChild(TemplateRef) detailRef;
...
}
Now, you can use the wrapper like this:
<my-wrapper>
<ng-template>
<my-component></my-component>
</ng-template>
</my-wrapper>
I am not sure, why it needs such complicated "workarounds", when it used to be so easy to do this in AngularJS.
By doing this:
<my-wrapper *ngIf="false">
<my-component></my-component>
</my-wrapper>
You are not calling MyComponent component, because the *ngIf is false. that means, that not calling it you are not instancing it and, therefore, not passing through its ngOnInit. And that's why you are not getting the console log.
By doing this:
<ng-container *ngIf="false">
<ng-content></ng-content>
</ng-container>
You are inside the component, you are just limiting what to render in your template, but you already instanced your component and, therefore, you passed through your ngOnInit and you get your console log done.
If, you want to limit something (component call with selector or a ng-content or even a div) until you have some data available, you can do the following:
datasLoaded: Promise<boolean>;
this.getData().subscribe(
(data) => {
this.datasLoaded = Promise.resolve(true); // Setting the Promise as resolved after I have the needed data
}
);
And in your template:
<ng-container *ngIf="datasLoaded | async">
// stuff here
</ng-container>
Or:
<my-component *ngIf="datasLoaded | async">
// Didn't test this one, but should follow the same logic. If it doesn't, wrap it and add the ngIf to the wrapper
</my-component>
It’s because Ng content happens at the build time and when you pass the content it is actually not removed or recreated with the ngIf directive. It is only moved and the component is instantiated .
I encountered this problem recently as well but settled on a different solution than the currently accepted one.
Solution (TL;DR)
(Solution is for AngularDart; I figure it's similar in Angular though)
Use a structural directive; tutorials linked below.
Instead of:
<my-wrapper>
<my-contents></my-contents>
</my-wrapper>
your usage becomes:
<div *myWrapper>
<my-contents></my-contents>
</div>
which is shorthand for the following (in AngularDart; I think Angular uses <ng-template>)
<template myWrapper>
<div>
<my-contents></my-contents>
</div>
</template>
The MyWrapper directive logic is similar to NgIf except it has its own logic to compute the condition. Both of the following tutorials explain how to create an NgIf-like directive and how to pass it your own inputs using the special microsyntax (e.g. *myWrapper="myInput: expression"). Note that the microsyntax doesn't support outputs (#Output), but you can mimic an output by using an input that is a function.
Tutorial for Angular
Tutorial for AngularDart
Caveat: Since this is just a directive, it shouldn't do anything more complicated than instantiating a template ref at the appropriate time and maybe specifying some DI providers. For example, I would avoid trying to apply styles or instantiating a complex tree of components in the directive. If I wanted to create a list component, I would probably take the #ContentChild(TemplateRef) approach described in another answer; you would lose the asterisk shorthand for creating <template> but you would gain the full power of components.
My problem
My team owns an app that's part of a larger web application with other apps owned by other teams. Our components assume they can inject a MyAppConfiguration object, but this object can only be injected after it is loaded with an asynchronous request. In our app this is not a problem: we have a "shell" component that hides everything behind an ngIf until the configuration is loaded.
The problem is when other teams want to reference our components. We don't want them to duplicate the "wait until configuration is loaded" logic every time, so I tried creating a wrapper component that can be used like so:
<my-app-wrapper>
<my-app-component></my-app-component>
</my-app-wrapper>
The wrapper injects a service object and hides its contents behind an ngIf until the service says that the configuration is loaded.
Like the question poster, I discovered that the ng-content approach doesn't work as intended: while the contents are correctly hidden from the DOM, Angular still instantiates the components causing dependency injection to fail.
The solution that I settled on was to rewrite the wrapper component as a structural directive.

Angular2 Templates: How to bind keydown.arrow to whole div instead of only control elements?

I have a simple navigator component with some buttons and a date-picker subcomponent. Now the idea is, that I can bind keydown.arrowleft etc. for the whole div (which has css style of 100% height and width). It's template looks like this:
<div id="ck-navigator" (keydown.arrowleft)="decrementDate();
$event.preventDefault()" (keydown.arrowright)="incrementDate();
$event.preventDefault()">
<button (click)="decrementDate()" class="fa fa-2x fa-chevron-left">
</button>
<ck-date-picker [date]="date" (dateChange)="changeDate($event)">
</ck-date-picker>
<button (click)="incrementDate()" class="fa fa-2x fa-chevron-right"></button>
</div>
I don't show the component code, it does not matter for this question (afaik).
This is working, but only if I actively select a button or the date-picker in advance (aka a control element). Is there a possibility to extend the keybinding to the whole div (i.e. if I just click somewhere on the site). Sorry for my lack of understanding the DOM and thanks for any push in the right direction.
The problem is that your div is not focusable so it isn't reacting to your keybindings. Try adding the attribute tabindex="0" to the div.
If what you want is to detect key events on the whole page what you need is probably to add #HostListener to your component. It is gona let you manage events in the whole page/window.
Seeing an example.
import { Component, HostListener } from '#angular/core';
[your #Component stuff ..... ]
#HostListener("window:keydown", ['$event'])
onKeyDown(event:KeyboardEvent) {
console.log(`Pressed ${event.key}!`);
}
Furthermore could help you to know that when you want to refer specific items you can use ElementRef class and ViewChild by importing them from angular/core. Then manage DOM components as:
#ViewChild('DOM_Id') element: ElementRef;
Maybe it helps. Peace