Can we use clr-dg-row inside the expandable row - vmware-clarity

In the example provided for expandable row in clarity, for MyDetailComponent , no <clr-dg-row-detail> tag is used in template. Is it okay to put any other tags like <clr-dg-row> cell info here..</clr-dg-row> without the <clr-dg-row-detail> in the MyDetailComponent template?? I tried it and it works fine but wanted to check if it's the right way or not...
#Component({
selector: "my-detail",
template: `
<div [ clrLoading ]="loading">...</div>
`
})
class MyDetailComponent implements OnInit {
#Input() user: User;
loading: boolean;
<clr-dg-row *ngFor="let user of users">
<-- Cells declarations -->
<clr-dg-cell>...
</clr-dg-cell>
<my-detail *clrIfExpanded [user]="user" ngProjectAs="clr-dg-row-detail">
</my-detail>
</clr-dg-row>

Related

Angular Component with Content Projection Not Loading Properly in Storybook until a Control Is Changed

I'm new to Storybook, and am having trouble getting components which project ng-content to correctly receive input arguments on initial load.
Template:
<div id="alert-card">
<div>
<div class="iconDiv" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="10px">
<mat-icon *ngIf='this.alertType === "Warning"' class="warningIcon" aria-hidden="false" aria-label="Warning">warning</mat-icon>
<mat-icon *ngIf='this.alertType === "Error"' class="errorIcon" aria-hidden="false" aria-label="Error">error</mat-icon>
<mat-icon *ngIf='this.alertType === "Info"' class="infoIcon" aria-hidden="false" aria-label="Info">info</mat-icon>
<mat-icon *ngIf='this.alertType === "Confirm"' class="confirmIcon" aria-hidden="false" aria-label="Confirm">check_circle</mat-icon>
<span><span class="alertType">{{ alertKeyword }}</span>{{ alertMessage }} </span>
</div>
<ng-content select="[cardContent]"></ng-content>
</div>
</div>
Component:
import {
Component,
Input,
ViewEncapsulation,
} from '#angular/core';
#Component({
selector: 'alert-card',
templateUrl: './alert-card.component.html',
styleUrls: ['./alert-card.component.scss'],
encapsulation: ViewEncapsulation.None,
})
// Displays the alert card
export class AlertCardComponent {
// The type of alert
#Input()
alertType: AlertType;
// The keyword at the start of the alert message
#Input()
alertKeyword: string;
// The alert message to display
#Input()
alertMessage: string;
constructor() {}
}
// Indicates a type of alert which has an associated icon and color scheme in the CSS
export enum AlertType {
Warning = "Warning",
Error = "Error",
Info = "Info",
Confirm = "Confirm",
}
Story:
import { componentWrapperDecorator, Meta, Story } from '#storybook/angular';
import { AlertCardComponent, AlertType } from './alert-card.component';
export default {
component: AlertCardComponent,
decorators: [componentWrapperDecorator(AlertCardComponent)],
} as Meta;
const Template: Story = (args) => ({
props: args,
template: `
<div cardContent
style="padding:10px"
fxLayoutAlign="center">
Arbitrary HTML content can go in this area
</div>
`
});
export const Warning = Template.bind({});
Warning.args= {
alertType: AlertType.Warning,
alertKeyword: "Warning: ",
alertMessage: "something has happened!"
};
This is nearly working as expected, but within the story, the component loads without any of the input arguments:
If I change any of the Storybook controls, the input arguments are passed and the component displays as expected:
I feel like I'm missing something obvious. Everything works as expected once I start manipulating the controls within Storybook, but how do I get the input arguments passed on initial load?
I'm also having what I believe are related issues on Storybook's Docs page. The component is displayed as it would without any arguments passed regardless of how the inputs are controlled.

In Angular, can I add css style together with double curly brackets?

I am trying to create a style for my element using a variable name, which is a number, and adding % at the end. I am currently doing it inline like this:
<progress-bar
style="{{batteryLifeLeft+'%'}}"
/>
What is wrong with it? Can you not add things together in this expression? I am getting the error: "Property value expected" and "at-rule or selector expected."
Correct syntax would be [ngStyle]="{'width.%': batteryLifeLeft}". https://angular.io/api/common/NgStyle
<div style="width: {{ batteryLifeLeft }}%">
{{ batteryLifeLeft }}% this wont work
</div>
<br />
<div [ngStyle]="{ 'width.%': batteryLifeLeft }">
{{ batteryLifeLeft }}% this will work
</div>
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
batteryLifeLeft = 50;
constructor() {}
}
Working example is on StackBlitz

Angular9 get parent node on element added with ng-container and ngIf

I am trying to get the parent element when a ng-template is added with ngIf.
Layout:
<section>
<h2>
Hello!
<ng-container *ngIf="someCondition1; then myTemplate"></ng-container>
</h2>
<div>
Another one!
<ng-container *ngIf="someCondition2; then myTemplate"></ng-container>
</div>
<!-- More markup here that show myTemplate based on conditions -->
</section>
<ng-template #myTemplate>
<img src="path/to/image.png" />
</ng-template>
The above works fine but I want to grab the parent element of wherever it's added and apply some styles to the parent in the typescript file. Can I use one of the lifecycle functions or select the parent another way whenever the template is added to the DOM?
I figured it out. I had to add a template tag on the image and then grab it with ViewChildren of type QueryList. This gave me access to the native element of each one where I could grab the parent node. This has to to be done in the AfterViewInit lifecycle hook.
HTML:
<section>
<h2>
Hello!
<ng-container *ngIf="someCondition1; then myTemplate"></ng-container>
</h2>
<!-- More markup here that show myTemplate based on conditions -->
</section>
<ng-template #myTemplate>
<img #myTemplateImage src="path/to/image.png" />
</ng-template>
Typescript:
import { Component, ViewChildren, ElementRef, QueryList, AfterViewInit } from '#angular/core';
#Component({
selector: 'test-selector',
templateUrl: './test.component.html'
})
export class TestComponent implements AfterViewInit {
#ViewChildren('myTemplateImage') imageList: QueryList<ElementRef>;
ngAfterViewInit() {
this.imageList.forEach((item) => {
item.nativeElement.parentNode.style.fontStyle = 'italic';
});
}
}

Angular: condition within ngClass attribute always treated as true

I'm trying to set the CSS class within 'EditDialogComponent' below (which is a modal view), depending on an input property called 'showMe' that is set from 'AppComponent':
HTML Code:
<div [ngClass]="showMe? 'ui active modal': 'ui modal'">
<i class="close icon"></i>
<div class="header">
Edit
</div>
<div class="actions">
<div class="ui black deny button">
Cancel
</div>
<div (click)="clk()" class="ui positive right labeled icon button">
OK
<i class="checkmark icon"></i>
</div>
</div>
</div>
TypeScript Code:
import { Component, Input, Output, OnInit } from '#angular/core';
#Component({
selector: 'edit-dialog',
templateUrl: './edit-dialog.component.html',
styleUrls: ['./edit-dialog.component.css']
})
export class EditDialogComponent implements OnInit {
#Input() subject: string
#Input() showMe: boolean
constructor() { }
clk() {
window.alert(this.showMe)
}
ngOnInit() {
}
}
This is the HTML code used to include 'EditDialogComponent' into 'AppComponent':
<edit-dialog showMe="{{show_edit_modal}}" subject='foobar'></edit-dialog>
The problem is that whenever I click on the 'OK' button of the modal, I get always the correct boolean value corresponding to show_edit_modal variable of AppComponent. Yet after testing, I found that ngClass keeps always treating the input value showMe as true.
Why ngClass is always treating the input property as true?
Your showMe input is not being properly bound to show_edit_modal.
Instead of:
<edit-dialog showMe="{{show_edit_modal}}" subject='foobar'></edit-dialog>
You should have:
<edit-dialog [showMe]="show_edit_modal" subject='foobar'></edit-dialog>
This will cause showMe to be set (and updated) by the parent's show_edit_modal.
Generally speaking, you should never need to use interpolation ({{ }}) inside any html tags. There is usually a different, more proper way of expressing what you need with Angular.

Angular2 Bind Attribute Value

Similar to Angular2 two-way data binding, I have a parent and a child component. In the parent I change the value that is passed to the child component via property. The property of the child is named percentage.
https://gist.github.com/ideadapt/59c96d01bacbf3222096
I want to bind the property value to a html attribute value. Like: <div style="width: {{percentage}}%">. I didn't find any syntax that worked. So I ended up using a change listener that does some manual DOM update:
this.progressElement = DOM.querySelector(element.nativeElement, '.progress');
DOM.setAttribute(this.progressElement, "style", `width: ${this.percentage}%`);
Is there a more elegant way to accomplish this?
You can use percentage binding for CSS properties: [style.width.%]
import {Component, Input} from 'angular2/core';
#Component({
selector: 'progress-bar',
template: `
<div class="progress-bar">
<div [style.width.%]="value"> {{ value }}% </div>
</div>
`,
})
export class ProgressBar {
#Input() private value: number;
}
Use NgStyle, which works similar to Angular 1. Since alpha-30, NgStyle is available in angular2/directives:
import {NgStyle} from 'angular2/directives';
Then include NgStyle in the directives list, this should work (here are some examples):
#View({
directives: [NgStyle]
template: `
<div class="all">
<div class="progress" [ng-style]="{'width': percentage + '%'}"></div>
<span class="label">{{percentage}}</span>
</div>
`
})
Alternatively and without using NgStyle, this would work well too:
<div class="progress" [style.width]="percentage + '%'"></div>

Resources