Angular2 how to pass reference for ngModel binding - binding

I wrote this component:
#Component({
selector: 'formfield',
template: `
<div>
<label>{{label}}</label>
<div>
<input class="form-control" type="text" [(ngModel)]="model">
</div>
</div>
`
})
export class Formfield {
#Input() label: string;
#Input() model: string;
}
I use it here:
<formfield label="something" model="somevalue"></formfield>
Not surprisingly the input field shows the string "somevalue". How can I make it to hold the value of the variable somevalue?

You need to use the following:
<formfield label="something" [model]="someprop"></formfield>
where someprop is a property of the component that uses the formfield component.
For example:
#Component({
(...)
})
export class SomeComponent {
someprop:string = 'some value';
}

Related

Angular Dart 2 - querySelect returning null

I'm trying to set up a drag&drop component to upload multiple files. However, when I attempt to access elements on the DOM with the querySelector method, I end up with null.
I've tried to implement the AfterViewInit class to no avail. Here's my current dart code for the component:
import 'dart:html';
import 'package:dnd/dnd.dart';
import 'package:angular/angular.dart';
#Component(
selector: 'upload',
templateUrl: 'upload.html',
styleUrls: [
'upload.css'
]
)
class Upload implements AfterViewInit {
#override
void ngAfterViewInit() {
// TODO: implement ngOnInit
Draggable d = new Draggable(document.querySelectorAll('.page'), avatarHandler : new AvatarHandler.clone());
var del = document.querySelector('.upload');
print(del); //prints null
Dropzone dropzone = new Dropzone(document.querySelector('.upload')); //throws an error, as it doesn't expect null.
dropzone.onDrop.listen((DropzoneEvent event){
print(event);
});
}
}
Also, my upload.html file is as follows:
<div class="center-me page" uk-grid>
<div class="uk-align-center text-align-center">
<h2 class="text-align-center" >Upload a file</h2>
<div class="upload uk-placeholder uk-text-center">
<span uk-icon="icon: cloud-upload"></span>
<span class="uk-text-middle">Attach binaries by dropping them here or</span>
<div uk-form-custom>
<input type="file" multiple>
<span class="uk-link">selecting one</span>
</div>
</div>
<progress id="progressbar" class="uk-progress" value="0" max="100" hidden></progress>
</div>
</div>
Thanks in advance.
So this looks like it should work. I wouldn't actually suggest doing it this way as it will get any element with an upload class which if you reuse the component will be a lot.
I would suggest using the ViewChild syntax instead
class Upload implements AfterViewInit {
#ViewChild('upload')
void uploadElm(HtmlElement elm) {
Dropzone dropzone = new Dropzone(elm);
dropzone.onDrop.listen((DropzoneEvent event){
print(event);
});
}
}
In the template:
<div class="uk-placeholder uk-text-center" #upload>
That said you shouldn't be getting null from the querySelect, but from the code you have shown I'm not sure why.

Angular Reactive Forms validations

I have a form with 3 inputs, 2 of the inputs are required and the third isn't.
My problem is that when I go the page of the form I see that the field that isn't required is in a valid state and is already colored with green, even tho the field isn't dirty or touched.
Is there anything I can do to make the input be grayed out until I validate the field / form or is it like this by design?
Here's the code I use in the component:
export class SystemSettingsComponent implements OnInit {
form: FormGroup;
constructor(private formBuilder: FormBuilder) {
this.form = new FormGroup({});
}
ngOnInit() {
this.form = this.formBuilder.group({
serviceName: ['', Validators.required],
serviceDesc: [''],
serviceId: [{value: SystemSettingsComponent.generateId(), disabled: true}, Validators.required]
});
}
static generateId() {
return Math.random().toString(36).substr(2, 9);
}}
And the template :
<form [formGroup]="form" novalidate>
<div class="row">
<div class="col-lg-4">
<mat-form-field>
<input matInput placeholder="שם השירות" formControlName="serviceName"/>
</mat-form-field>
<mat-form-field>
<textarea matInput placeholder="תיאור השירות" formControlName="serviceDesc"></textarea>
</mat-form-field>
<mat-form-field>
<input matInput class="ltr text-align-left" placeholder="מזהה שירות" formControlName="serviceId"/>
</mat-form-field>
</div>
</div>
<div>
<button mat-raised-button class="mat-raised-button mat-primary" matStepperNext>הבא</button>
</div>
You can listen to the form's status changes and set the optional form control's disabled state accordingly. Something like:
ngOnInit() {
this.form = this.formBuilder.group({
serviceName: ['', Validators.required],
serviceDesc: [{value: '', disabled: true}],
serviceId: [{value: SystemSettingsComponent.generateId(), disabled: true}, Validators.required]
});
this.form.statusChanges.subscribe(status => {
if (status === 'VALID' && this.form.controls.serviceDesc.disabled) {
this.form.controls.serviceDesc.enable();
} else if (status !== 'VALID' && this.form.controls.serviceDesc.enabled) {
this.form.controls.serviceDesc.disable();
}
});
}

Getting child form values in parent component, onclick of a button present in parent component

I have a parent component like this
<div>
<div class="selection-area active" style="max-height:initial;" contact-details [(contactDetailsD)]="conDetailsUI"></div>
</div>
<div>
Next
</div>
The child component
<div>
<form>
<input type="text" name="name" value="{{contactDetailsD?.firstName}}">
<input type="text" name="email" value="{{contactDetailsD?.email}}">
<input type="text" name="phone" value="{{contactDetailsD?.phone}}">
</form>
</div>
Can you help me to get the child form values in parent component, onclick of Next button that present in the parent component.
Use services.. Have some getters and setters in the services and inject the service in the parent component set the values and inject the service in the child component and get the values and assign them to some variables and bind them in the template. Here is the example of service
import { Injectable } from '#angular/core';
#Injectable()
export class ActiveclassService {
constructor() { }
private rolesclass:any;
setrolesclass(rolesclass){
this.rolesclass=rolesclass;
}
getrolesclass(){
return this.rolesclass;
}
Parent listens for child event
The child component exposes an EventEmitter property with which it emits events when something happens. The parent binds to that event property and reacts to those events.
The child's EventEmitter property is an output property, typically adorned with an #Output decoration as seen in this VoterComponent:
import { Component, EventEmitter, Input, Output } from '#angular/core';
#Component({
selector: 'my-voter',
template: `
<h4>{{name}}</h4>
<button (click)="vote(true)" [disabled]="voted">Agree</button>
<button (click)="vote(false)" [disabled]="voted">Disagree</button>
`
})
export class VoterComponent {
#Input() name: string;
#Output() onVoted = new EventEmitter<boolean>();
voted = false;
vote(agreed: boolean) {
this.onVoted.emit(agreed);
this.voted = true;
}
}
Clicking a button triggers emission of a true or false, the boolean payload.
The parent VoteTakerComponent binds an event handler called onVoted() that responds to the child event payload $event and updates a counter. VoterParentComponet:
import { Component } from '#angular/core';
#Component({
selector: 'vote-taker',
template: `
<h2>Should mankind colonize the Universe?</h2>
<h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
<my-voter *ngFor="let voter of voters"
[name]="voter"
(onVoted)="onVoted($event)">
</my-voter>
`
})
export class VoteTakerComponent {
agreed = 0;
disagreed = 0;
voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'];
onVoted(agreed: boolean) {
agreed ? this.agreed++ : this.disagreed++;
}
}
SRC: https://angular.io/guide/component-interaction#parent-listens-for-child-event

angular2 async validation this.subscribe exception?

I try to implement async(isUnique) and sync(cannotContainSpace) validation functions for username field, I want to see "this username already in use alert msg, if textbox value is "yener". sync function works fine but i think ss below can help explain my issue;
Note:canNotContain sync validation func works fine, aafter I added isUnique async function this exception occured..
how can I fix it ?
usernamevalidator.ts
import {FormControl} from '#angular/forms';
export class UsernameValidator{
static isUnique(control:FormControl){
return new Promise((resolve, reject)=>{
setTimeout(function(){
debugger
if(control.value =="yener")
resolve({isUnique:true})
else
resolve(null)
},1000);
});
}
static cannotContainSpace(control:FormControl){
if(control.value.indexOf(' ')>=0)
return { cannotContainSpace:true };
return null;
}
}
postmessage.component.ts
import { Component } from '#angular/core';
import {FormControl,FormGroup,FormBuilder,Validators} from '#angular/forms';
import {UsernameValidator} from '../../validators/usernamevalidator';
#Component({
moduleId:module.id,
selector: 'post-message',
templateUrl: '../../templates/postmessage.component.html'
})
export class PostComponent {
form : FormGroup;
constructor(fb:FormBuilder){
this.form = fb.group({
username:['', Validators.compose([Validators.required, UsernameValidator.cannotContainSpace]),Validators.compose([UsernameValidator.isUnique])],
email:['', Validators.required],
message:['', Validators.required]
});
}
signup(){
console.log(this.form.value);
}
}
here is html template:
<form class="from-horizontal" [formGroup]="form" (ngSubmit)="signup()">
<div class="form-group row">
<label for="username" class="control-label col-md-2">Name:</label>
<div class="col-md-6">
<input type="text" id="username" class="form-control" formControlName="username">
<div *ngIf="form.controls['username'].touched && form.controls['username'].errors">
<div class="alert alert-danger"
*ngIf="form.controls['username'].errors.required">
User name is required.
</div>
<div class="alert alert-danger"
*ngIf="form.controls['username'].errors.cannotContainSpace">
User name can not contain space
</div>
<div class="alert alert-danger" *ngIf="form.controls['username'].errors.isUnique">
This user name already in use.
</div>
</div>
</div>...
it's strange, i though we can use "Validators.compose()" function in form builder initializer as async parameters but angular2 dont agree with me..
I just changed;
username:['', Validators.compose([Validators.required,
UsernameValidator.cannotContainSpace]),Validators.compose([UsernameValidator.isUnique])],
to
username:['', Validators.compose([Validators.required,
UsernameValidator.cannotContainSpace]),UsernameValidator.isUnique],
and it works
EDITED:
also I figured out if you want to use multiple async validators in a component use
Validators.composeAsync()
function.

Input onchange with Angular2

I try to detect on change with dart. Example html:
<div>
<input id="photoUpload" type="file" name="photo" (onchange)="update()" multiple>
</div>
Dart:
#Component(
selector: "photo-upload-dialog", templateUrl: "photo_upload_dialog.html")
class PhotoUploadDialog {
update() async {
print('Changed!');
}
}
But nothing in a console.
onChange is the default event handler name, not the event name.
Use instead
(change)="update()"

Resources