Angular2 MDL disabling mdl-menu-item not working - angular2-mdl

I am trying to disable mdl-menu-item based on condition set by module.
my app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'ca-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
test() {
return true;
}
}
my app.component.html
<button mdl-button #btn1="mdlButton" (click)="m1.toggle($event, btn1)" mdl-button-type="raised" mdl-ripple>Options</button>
<mdl-menu #m1="mdlMenu" mdl-menu-position="top-left">
<mdl-menu-item mdl-ripple [disabled]="test()">Draw Object</mdl-menu-item>
<mdl-menu-item mdl-ripple mdl-menu-item-full-bleed-divider>Another Action</mdl-menu-item>
<mdl-menu-item mdl-ripple disabled>Disabled Action</mdl-menu-item>
<mdl-menu-item>Yet Another Action</mdl-menu-item>
</mdl-menu>
At this stage the menu item is never disabled, not sure what i am doing wrong here.

The disabled attribute is a ui only feature in material design lite. e.g. there are only some css rules that change the ui if the disabled attribute is present on an mdl-menu-item. So in your case you can do the following:
<mdl-menu-item [attr.disabled]="test() ? '' : null">Draw Object</mdl-menu-item>
The null value removes the attribute. Also you should note that the click event is fired in any case.
This could be improved but I think I would break existing behavior. I have filed an issue for the next major release to make it more angular like (https://github.com/mseemann/angular2-mdl/issues/797).

Related

Angular variable in component not rendering in template

Answer: I was using title: 'myTitle' instead of title = 'myTitle' ;(
I have just generated a new Angular app with one new component.
The problem is when i initialize a variable inside the class component and try to output it in the template using {{}} it is not showing variable's value.
In the main - App-Root Component it is written just like my code but there it is working :(
content.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-content',
templateUrl: './content.component.html',
styleUrls: ['./content.component.sass']
})
export class ContentComponent {
title: 'Content'
}
content.component.html
<h3>{{title}}</h3>
This is how you should bind values :
In component.ts :
public title:any = 'Content';
in component.html :
<h1> {{title}} </h1>
Here is a working example : demo
Use the angular variable as below
title: string="Content"
For eg
Try this, I have created a sample MyComponent class as below.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent implements OnInit {
private myVariable:string="Hello World"
constructor() { }
ngOnInit() {
}
}
my-component.component.html
<p>
{{myVariable}}
</p>
Make sure add the above component in app.component.html which is the bootstrapping component as below
<app-my-component></app-my-component>
also in app.module as below in declartion section
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
MyComponentComponent
],
bootstrap: [ AppComponent ]

Cannot register svg icon

I would like to register a new Material2 icon, I have this code:
import {Component, OnInit} from '#angular/core';
import {MatIconRegistry} from '#angular/material/icon';
import {DomSanitizer} from '#angular/platform-browser';
#Component({
selector: 'app-control-panel',
templateUrl: './control-panel.component.html',
styleUrls: ['./control-panel.component.scss']
})
export class ControlPanelComponent implements OnInit {
constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
console.log('registering play button icon'); // << confirm
iconRegistry.addSvgIcon('play_button',
sanitizer.bypassSecurityTrustResourceUrl('assets/images/play-button.svg'));
}
ngOnInit() {
}
}
the log statement above is being hit. And I have this HTML
<button mat-raised-button color="accent">
<mat-icon>play_button</mat-icon>
Start Recording
</button>
if I use an existing icon it works, but if I use "play_button" it doesn't work.
Anyone know what might be going wrong?
<mat-icon> should set the svgIcon property. i.e.:
<mat-icon svgIcon="play_button"></mat-icon>
MatIconRegistry should be imported from #angular/material
Ensure that you import HttpClientModule in app.module.ts so the asset you're requesting can be downloaded.

How to show a Kendo UI for Angular combobox open and use an *ngIf directive in it

ComboBoxComponent provides the method toggle that toggles the visibility of the comboBox popup. I want to display comboBox already opened. I have the following implementation:
datalist.component.html
<kendo-combobox #attributecombobox></kendo-combobox>
datalist.component.cs
#Component({
templateUrl: './datalist.component.html'
})
export class DatalistComponent implements OnInit {
#ViewChild('attributecombobox') public attributeCombobox: ComboBoxComponent;
}
I've tried setting the constructor:
constructor() {
this.attributeCombobox.toggle(true);
}
Doesn't work. I also tried the OnInit lifecycle hook:
ngOnInit() {
this.attributeCombobox.toggle(true);
}
It also does not work.
What is the right approach for this? Thanks in advance.
Update 1
Sorry, I didn't disclose all the code. The ComboBox actually has a *ngIf:
datalist.component.html
<kendo-combobox #attributecombobox *ngIf="setAttribute"></kendo-combobox>
datalist.component.cs
#Component({
templateUrl: './datalist.component.html'
})
export class DatalistComponent implements OnInit {
#ViewChild('attributecombobox') public attributeCombobox: ComboBoxComponent;
setAttribute = true;
ngOnInit() {
this.attributeCombobox.toggle(true);
}
}
So I think that I found an issue with kendo-combobox elements using *ngIf as you can see in this plunker that I forked from George K plunker (thanks George).
Update 2
I submitted an issue which was classified as a bug here.
The earliest possible place to open the component is in the ngOnInit (your second attempt). Calling the toggle method works just fine for me:
ngOnInit() {
this.combo.toggle();
}
Here is a runnable plunker:
http://plnkr.co/edit/ssbftD6hg3f7LM86CIPD?p=preview
Update
Indeed, the component will not be available in ngOnInit hook if a structure directive like ngIf is applied. Basically, this will desugar to
<ng-template [ngIf]="show">....combobox here... </ng-template>
As you've probably already noticed, the component inside the template will not be there on first init. The solution is to use a hook that will be called later in the component initialization, like AfterViewInit:
ngAfterViewInit() {
setTimeout(() => {
this.combo.toggle();
});
}
The updated plunkr demo can be found here - http://plnkr.co/edit/quLb3oeiVRJfqACqGKEK?p=preview

Can I Create Nested Angular Component HTML Selectors?

Updated: Per Thierry Templier's response:
Below is essentially what I want to do, but unfortunately the inner components aren't rendering. Is there a way to nest components via their HTML selectors like so?
<custom-menu-bar-component (onCustomEvent)="handleEvent($event)">
<custom-button-component></custom-button-component>
<custom-dropdown-component></custom-dropdown-component>
</custom-menu-bar-component>
In my chrome debugger, I see only the outer component being rendered:
<custom-menu-bar-component>
<div class="row">
** Nothing here, where my two inner components should be :(
</div>
</custom-menu-bar-component>
And my components look like this:
CustomMenuBarComponent.ts:
import {Component} from 'angular2/core'
import {CustomButtonComponent} from './CustomButtonComponent'
import {CustomDropdownComponent} from './CustomDropdownComponent'
#Component({
selector: 'custom-menu-bar-component',
directives: [CustomButtonComponent, CustomDropdownComponent],
template: `
<div class="row"></div>
`
})
export class CustomMenuBarComponent {
}
CustomButtonComponent.ts:
import {Component, EventEmitter} from 'angular2/core'
import {CustomEvent} from './CustomEvent'
#Component({
selector: 'custom-button-component',
outputs: ['onCustomEvent'],
template: `
<button type="button" class="btn btn-light-gray" (click)="onItemClick()">
<i class="glyphicon icon-recent_activity dark-green"></i>Button</button>
`
})
export class CustomButtonComponent {
onCustomEvent: EventEmitter<CustomEvent> = new EventEmitter();
onItemClick(): void {
this.onCustomEvent.emit(new CustomEvent("Button Component Clicked"));
}
}
CustomDropdownComponent is nearly identical to the CustomButtonComponent, but with different text. I'm just trying to get this very simple example working before I start making these components more useful and reusable.
Is this kind of approach possible? I'm trying to make it easy for others to take these components and create more of my custom menu bars with ease and simplicity.
Not sure what your question is about but
<custom-menu-bar-component (onCustomEvent)="handleEvent($event)">
<custom-button-component></custom-button-component>
<custom-dropdown-component></custom-dropdown-component>
</custom-menu-bar-component>
requires <ng-content></ng-content> in the template of CustomMenuBarComponent
A bit of documentation can be found in https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#aftercontent I had expected a bit more this was all I found.
http://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html might contain some helpful information as well.
Update
Moving (onCustomEvent)="handleEvent($event)" to the <custom-button-component></custom-button-component> element should do what you want. Events from EventEmitter don't bubble.
In fact you have the error because you don't instantiate your EventEmitter in the CustomButtonComponent component:
#Component({
(...)
})
export class CustomButtonComponent {
onCustomEvent: EventEmitter<CustomEvent> = new EventEmitter(); // <-----
(...)
}
Otherwise your code seems correct.
Update
You need to use ng-content to include your sub components into the CustomMenuBarComponent one.
#Component({
selector: 'custom-menu-bar-component',
directives: [CustomButtonComponent, CustomDropdownComponent],
template: `
<div class="row">
<ng-content></ng-content>
</div>
`
})
export class CustomMenuBarComponent {
}

center paper-dialog upon opening

I'm trying to create a simple login window using Angular 2 and Polymer 1.0.2.
It's basically a paper-dialog (login window) with content. The dialog however is not positioned in the center of the screen, see this bugreport Dialog not centered until window resize #36:
The issue suggests calling the notifyResize() method on the paper-dialog. But I've no clue as how to refer to the paper-dialog instance in my angular 2/polymer class.
Somehow the import {PaperDialog} is not resolved, but looking in the paper-dialog.html makes me wondering if such an import is possible at all.
import {Component, View} from 'angular2/angular2';
import {PaperDialog} from 'bower_components/paper-dialog/paper-dialog';
#Component({
template: `
<paper-dialog open>
...
</paper-dialog>
`,
selector: 'login-window',
directives : [PaperDialog]
})
export class LoginWindow {
email: string;
password: string;
constructor(){
this.email = '';
this.password = '';
// Where and how to call the PaperDialog child's notifyResize() method
}
}
Note that I'm not opening the dialog programmatically (fix described here).
This solution uses the /deep/ selector that is deprecated.
And it shouldn't be fixed by applying some css, should it?
Instead of having my code fix the paper-dialog behaviour's code, it's way better to fix the problem itself.
Add the call this.notifyResize(); to the _onIronOverlayOpened method in the paper-dialog-behavior.html source.
...
_onIronOverlayOpened: function() {
if (this.modal) {
document.body.addEventListener('focus', this._boundOnFocus, true);
this.backdropElement.addEventListener('click', this._boundOnBackdropClick);
}
this.notifyResize(); // Added this line
},
...
Although this resolves my simple paper-dialog center problem, I can not oversee consequences for other elements and code yet.
You could also fix it in the following manner:
Within an angular2 Component (that wraps the paper-dialog element) you could so something like this (Typescript example):
interface PaperDialog extends HTMLElement {
notifyResize(): void;
}
#Component({
selector: 'login'
})
#View({
templateUrl: 'app/components/ts-login-window/ts-login-window.html'
})
export class LoginWindow {
email: string;
password: string;
dialogWindow: PaperDialog;
private bindIronOverlayOpened: EventListenerObject;
constructor(elementRef: ElementRef){
this.dialogWindow = elementRef.nativeElement.children[0];
this.bindIronOverlayOpened = this.ironOverlayOpened.bind(this);
this.dialogWindow.addEventListener('iron-overlay-opened', this.bindIronOverlayOpened);
}
ironOverlayOpened(event: Event) {
this.dialogWindow.notifyResize();
}
onDestroy() {
this.dialogWindow.removeEventListener('iron-overlay-opened', this.bindIronOverlayOpened);
}
}
Once the paper-dialog has been opened (by the event iron-overlay-opened) you could trigger the notifyResize() event on the dialog box. This in turn fixes the alignment problem.

Resources