Good Morning,
I'm new to Angular and happily learning away.
I'm successfully loading form into my Modal on a "viewDetails" click.
However when I make a slight change to the Form from <form ngNoForm > to <form #editCashMovementForm="ngForm"> the data no longer loads.
I'm trying to make an editable pop-up form that updates on submit but its just this last step that I'm failing on.
Does anybody have advice please?
Thanks
Gws
Component.HTML
<div>
<table class="table table-hover">
<thead>
<tr>
<th><i class="fa fa-text-width fa-2x" aria-hidden="true"></i>Cash Movement ID</th>
<th><i class="fa fa-user fa-2x" aria-hidden="true"></i>PortfolioCode</th>
<th><i class="fa fa-paragraph fa-2x" aria-hidden="true"></i>CCY Out</th>
<th><i class="fa fa-map-marker fa-2x" aria-hidden="true"></i>Account Out</th>
<th><i class="fa fa-calendar-o fa-2x" aria-hidden="true"></i>Date</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let cashmovement of cashmovements">
<td> {{cashmovement.cashMovementId}}</td>
<td>{{cashmovement.portfolioCode}}</td>
<td>{{cashmovement.ccyo}}</td>
<td>{{cashmovement.accountO}}</td>
<td>{{cashmovement.date | dateFormat | date:'medium'}}</td>
<td><button class="btn btn-danger" (click)="removeCashMovement(cashmovement)"><i class="fa fa-trash" aria-hidden="true"></i>Delete</button></td>
<td><button class="btn btn-primary" (click)="viewCashMovementDetails(cashmovement.cashMovementId)"><i class="fa fa-info-circle" aria-hidden="true"></i>Edit</button></td>
</tr>
</tbody>
</table>
</div>
<div bsModal #childModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" *ngIf="selectedCashMovementLoaded">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" aria-label="Close" (click)="hideChildModal()"><span aria-hidden="true">×</span></button>
<h4>{{cashmovementDetails.cashMovementId}} Details</h4>
</div>
<div class="modal-body">
<form ngNoForm >
<!--<form #editCashMovementForm="ngForm" (ngSubmit)="updateCashMovement(editCashMovementForm)">-->
<div class="form-group">
<div class="row">
<div class="col-md-4">
<label class="control-label"><i class="fa fa-user" aria-hidden="true"></i>Portfolio Code</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.portfolioCode" />
</div>
<div class="col-md-4">
<label class="control-label"><i class="fa fa-text-width" aria-hidden="true"></i>Currency Out</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.ccyo" />
</div>
<div class="col-md-4">
<label class="control-label"><i class="fa fa-paragraph" aria-hidden="true"></i>Account Out</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.accountO" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="control-label"><i class="fa fa-calendar-o" aria-hidden="true"></i>Date</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.date" />
</div>
</div>
</div>
<hr/>
<button type="button" [disabled]="!editCashMovementForm.form.valid" class="btn btn-default" (click)="updateCashMovement(editCashMovementForm)"><i class="fa fa-pencil-square-o" aria-hidden="true"></i>Update</button>
</form>
</div>
</div>
</div>
</div>
Component.ts
import { Component, OnInit, ViewChild, Input, Output, trigger, state, style, animate, transition } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { NgForm } from '#angular/forms';
import { ModalDirective } from 'ng2-bootstrap';
import { CashMovementDataService } from './cashmovement.data.service';
import { DateFormatPipe } from '../shared/pipes/date-format.pipe';
import { ItemsService } from '../shared/utils/items.service';
import { NotificationService } from '../shared/utils/notification.service';
import { ConfigService } from '../shared/utils/config.service';
import { MappingService } from '../shared/utils/mapping.service';
import { ICashMovement, Pagination, PaginatedResult } from '../shared/interfaces';
#Component({
moduleId: module.id,
selector: 'cashmovements',
templateUrl: './cashmovement-list.component.html'
})
export class CashMovementListComponent implements OnInit {
#ViewChild('childModal') public childModal: ModalDirective;
cashmovements: ICashMovement[];
// Modal properties
#ViewChild('modal')
modal: any;
items: string[] = ['item1', 'item2', 'item3'];
selected: string;
output: string;
selectedCashMovementId: number;
cashmovementDetails: ICashMovement;
selectedCashMovementLoaded: boolean = false;
index: number = 0;
backdropOptions = [true, false, 'static'];
animation: boolean = true;
keyboard: boolean = true;
backdrop: string | boolean = true;
constructor(private route: ActivatedRoute,
private router: Router,
private dataService: CashMovementDataService,
private itemsService: ItemsService,
private notificationService: NotificationService,
private configService: ConfigService,
private mappingService: MappingService) { }
ngOnInit() {
this.loadCashMovements();
}
loadCashMovements(){
this.dataService.getCashMovements()
.subscribe((cashmovements: ICashMovement[]) => {
this.cashmovements = cashmovements;
},
error => {
this.notificationService.printErrorMessage('Failed to load cashmovements. ' + error);
});
}
removeCashMovement(cashmovement: ICashMovement) {
this.notificationService.openConfirmationDialog('Are you sure you want to delete this cashmovement?',
() => {
this.dataService.deleteCashMovement(cashmovement.cashMovementId)
.subscribe(() => {
this.itemsService.removeItemFromArray<ICashMovement>(this.cashmovements, cashmovement);
this.notificationService.printSuccessMessage(cashmovement.cashMovementId + ' has been deleted.');
},
error => {
this.notificationService.printErrorMessage('Failed to delete ' + cashmovement.cashMovementId + ' ' + error);
});
});
}
viewCashMovementDetails(id: number) {
this.selectedCashMovementId = id;
this.dataService.getCashMovement(this.selectedCashMovementId)
.subscribe((cashmovement: ICashMovement) => {
this.cashmovementDetails = this.itemsService.getSerialized<ICashMovement>(cashmovement);
this.cashmovementDetails.date = new DateFormatPipe().transform(cashmovement.date, ['local']);
this.selectedCashMovementLoaded = true;
this.childModal.show();
},
error => {
this.notificationService.printErrorMessage('Failed to load cashmovement. ' + error);
});
}
updateCashMovement(editCashMovementForm: NgForm) {
var scheduleMapped = this.mappingService.mapCashMovementDetailsToCashMovement(this.cashmovementDetails);
this.dataService.updateCashMovement(scheduleMapped)
.subscribe(() => {
this.notificationService.printSuccessMessage('Cash Movement has been updated');
},
error => {
this.notificationService.printErrorMessage('Failed to update cash movement. ' + error);
});
}
public hideChildModal(): void {
this.childModal.hide();
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { Http, Response, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { ICashMovement, ICashMovementDetails, Pagination, PaginatedResult } from '../shared/interfaces';
import { ItemsService } from '../shared/utils/items.service';
import { ConfigService } from '../shared/utils/config.service';
#Injectable()
export class CashMovementDataService {
_baseUrl: string = '';
constructor(private http: Http,
private itemsService: ItemsService,
private configService: ConfigService) {
this._baseUrl = configService.getApiURI();
}
getCashMovements(): Observable<void> {
return this.http.get(this._baseUrl + 'cashmovements')
.map((res: Response) => { return res.json(); })
.catch(this.handleError);
}
deleteCashMovement(id: number): Observable<void> {
return this.http.delete(this._baseUrl + 'cashmovements/?id=' + id)
.map((res: Response) => {
return;
})
.catch(this.handleError);
}
getCashMovement(id: number): Observable<ICashMovement> {
return this.http.get(this._baseUrl + 'cashmovements/?id=' + id)
.map((res: Response) => {
return res.json();
})
.catch(this.handleError);
}
updateCashMovement(cashmovement: ICashMovement): Observable<void> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.put(this._baseUrl + 'cashmovements/?id=' + cashmovement.cashMovementId, JSON.stringify(cashmovement), {
headers: headers
})
.map((res: Response) => {
return;
})
.catch(this.handleError);
}
private handleError(error: any) {
var applicationError = error.headers.get('Application-Error');
var serverError = error.json();
var modelStateErrors: string = '';
if (!serverError.type) {
console.log(serverError);
for (var key in serverError) {
if (serverError[key])
modelStateErrors += serverError[key] + '\n';
}
}
modelStateErrors = modelStateErrors = '' ? null : modelStateErrors;
return Observable.throw(applicationError || modelStateErrors || 'Server error');
}
}
I need to change my form inputs from
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.portfolioCode" />
To
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.portfolioCode" name="portfolioCode" #portfolioCode="ngModel"/>
Related
I am working through the challenges for a Udemy course on Angular 4, but I am stuck on a challenge where I have to create an input for a new password and then another input to confirm the new password using reactive forms.
I have an external .ts file called password.validators.ts that has custom form validation code, and I can get the value of the currently selected input box by passing a control object with AbstractControl, but how do I pass a value to my component.ts file and then from my component.ts to my password.validators.ts ? I need to be able to compare the new password value to the confirm password value and I'm stuck!
new-password.component.html
<form [formGroup]="form">
<div class="form-group">
<label for="oldPassword">Old Password</label>
<input
formControlName="oldPassword"
id="oldPassword"
type="text"
class="form-control">
<div *ngIf="oldPassword.pending">Checking password...</div>
<div *ngIf="oldPassword.touched && oldPassword.invalid" class="alert alert-danger">
<div *ngIf="oldPassword.errors.required">Old password is required</div>
<div *ngIf="oldPassword.errors.checkOldPassword">Password is incorrect</div>
</div>
</div>
<div class="form-group">
<label for="newPassword">New password</label>
<input
formControlName="newPassword"
id="newPassword"
type="text"
class="form-control">
<div *ngIf="newPassword.touched && newPassword.invalid" class="alert alert-danger">
<div *ngIf="newPassword.errors.required">New password is required</div>
</div>
</div>
<div class="form-group">
<label for="confirmNewPassword">Confirm new password</label>
<input
formControlName="confirmNewPassword"
id="confirmNewPassword"
type="text"
class="form-control">
<div *ngIf="confirmNewPassword.touched && confirmNewPassword.invalid" class="alert alert-danger">
<div *ngIf="confirmNewPassword.errors.required">Confirm password is required</div>
<div *ngIf="confirmNewPassword.errors.confirmNewPassword">Passwords don't match</div>
</div>
</div>
<button class="btn btn-primary" type="submit">Change Password</button>
</form>
new-password.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { PasswordValidators } from './password.validators';
#Component({
selector: 'new-password',
templateUrl: './new-password.component.html',
styleUrls: ['./new-password.component.css']
})
export class NewPasswordComponent {
form = new FormGroup({
oldPassword: new FormControl('', Validators.required, PasswordValidators.checkOldPassword),
newPassword: new FormControl('', Validators.required),
confirmNewPassword: new FormControl('', Validators.required )
})
get oldPassword() {
return this.form.get('oldPassword');
}
get newPassword() {
return this.form.get('newPassword');
}
get confirmNewPassword() {
return this.form.get('confirmNewPassword');
}
addNewPassword(newPassword: HTMLInputElement) {
let np = this.newPassword;
return np;
}
}
password.validators.ts
import { AbstractControl, ValidationErrors } from '#angular/forms';
export class PasswordValidators {
static checkOldPassword(control: AbstractControl) : Promise<ValidationErrors | null> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(control.value !== '1234')
resolve({ checkOldPassword: true }) ;
else resolve(null);
}, 2000);
});
}
static confirmNewPassword(control: AbstractControl) : ValidationErrors | null {
if(control.value === control.newPassword.value)
return null;
}
}
I have used the following code for my password validation may be this can help you
In password.validator write this code
import {AbstractControl} from '#angular/forms';
export class PasswordValidation {
static MatchPassword(AC: AbstractControl) {
let password = AC.get('password').value;
let confirmPassword = AC.get('confirmPassword').value;
if(password != confirmPassword) {
console.log('false');
AC.get('confirmPassword').setErrors( {MatchPassword: true} )
} else {
console.log('true');
return null
}
}
}
and in the component file use this code
constructor(fb: FormBuilder)
{
this.form = fb.group({
password: ['', Validators.required],
confirmPassword: ['', Validators.required]
}, {
validator: PasswordValidation.MatchPassword // your validation method
})
}
and in html file to find error use this code
<div class="alert alert-danger" *ngIf="form.controls.confirmPassword.errors?.MutchPassword">Password not match</div>
Hope it would help you
There is a short time between the posting and the response from the server. How is it possible to cause your component to re-render when you get your positive response? I tried componentWillGetProps(){} and if-statements like
if(this.props.incomingItems){return: this.props.incomingItems}
but it none of them worked out. How did you solve this problem?
PS I'm using redux and axios for the requests.
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import * as actions from '../../actions';
class eventView extends Component {
componentWillMount() {
this.props.eventView(this.props.params.eventID);
}
createNewRole(roleName){
this.props.createNewRole(roleName, this.props.params.eventID);
};
renderUsers(){
return this.props.eventDetails.userList.map((user)=>{
return(
<li className='list-group-item eventUserList' background-color="#f2f2f2" key={user._id}>
{user.userName}
</li>
);
});
};
deleteListItem(key){
const newKey = key.dispatchMarker.substr(44, 24);
this.props.RemoveRoleFromList(newKey)
this.props.fetchEvents();
}
renderRoles(){
return this.props.eventDetails.role.map((role)=>{
return(
<li className='list-group-item roleList' key={role._id}>
{role.roleName}
<img className="deleteListItem"
src="/img/trash.png"
key={role._id}
onClick={this.deleteListItem.bind(this)}/>
</li>
);
});
};
render() {
const { handleSubmit, fields: {eventName,location, eventPassword, roleName} } = this.props;
if(this.props.roleList){
console.log(this.props.roleList)
}
if (this.props.eventDetails){
return (
<div className='container-fluid'>
<div className="roleBox">
<form onSubmit={handleSubmit(this.createNewRole.bind(this))}>
<div>
<input {...roleName}
className="form-control roleBoxInputBar"
autoComplete="off"/>
<button className="RoleButton">Save</button>
</div>
<div className="listOfRoles">
<ul className="listOfRoles pre-scrollable">
{this.renderRoles()}
</ul>
</div>
</form>
</div>
<div>
<div>
<h1 className="eventName">
{this.props.eventDetails.eventName}
</h1>
</div>
<br/>
<table>
<tbody>
<tr>
<td className="eventViewTableLocation">Location:</td>
<td className="eventViewTable">{this.props.eventDetails.location}</td>
</tr>
<tr>
<td className="eventViewTableLocation">Date:</td>
<td className="eventViewTable">12/Feb/2018</td>
</tr>
<tr>
<td className="eventViewTableLocation">Time Left:</td>
<td className="eventViewTable">2 Days 2 Hours</td>
</tr>
</tbody>
</table>
</div>
<div className='eventViewUserBox'>
<h4 className="listOfUsers">Organisers:</h4>
<ul>
{this.renderUsers()}
</ul>
</div>
</div>
);
}else {
return (
<div>
</div>
);
}
}
}
function mapStateToProps(state) {
return { eventDetails: state.api.eventDetails };
return { roleList: state.api.roleList };
return { createdRole: state.api.createdRole };
}
export default reduxForm({
form: 'eventView',
fields: ['eventName', 'location', 'eventPassword', 'roleName']
}, mapStateToProps, actions)(eventView);
And my axios post goes something like this
export function createNewRole({roleName}, eventID){
return function(dispatch) {
axios.post(`${ROOT_URL}createRole/`+eventID, {roleName})
.then(response => {
if (response.data){
dispatch({
type: CREATED_ROLE,
payload: response.data,
});
};
})
.catch(response => dispatch(authError(response.data.error)));
};
};
Reducer:
export default function(state = {}, action) {
switch(action.type) {
case FETCH_ROLES:
return { ...state, roleList: action.payload };
case CREATED_ROLE:
return { ...state, createdRole: action.payload };
}
return state;
}
Thanks a lot!
function mapStateToProps(state) {
return { eventDetails: state.api.eventDetails };
return { roleList: state.api.roleList };
return { createdRole: state.api.createdRole };
}
This function always returns the first object. It should be:
function mapStateToProps(state) {
return {
eventDetails: state.api.eventDetails,
roleList: state.api.roleList,
createdRole: state.api.createdRole
};
}
I'm guessing roleList and createdRole are always undefined? Also it would be good if you would show the reducer.
hi every body i am using angular 4 , when i save form in deployment mode, i get the error down , and when i save the same form in development mode i don't get the exception.
my form code products-form.component.ts :
import {Component, OnInit, OnDestroy, ViewChild, ElementRef} from '#angular/core';
import {NgForm} from '#angular/forms';
import {AdminService} from "../../../services/admin.service";
import {HttpService} from "../../../../http.service";
import {Subscription} from "rxjs";
import {Http, Response, Headers,RequestOptions} from "#angular/http";
import {ActivatedRoute, Router} from "#angular/router";
import { trigger, state, style, transition, animate } from '#angular/animations';
import {BrowserAnimationsModule} from '#angular/platform-browser/animations';
import {BusyModule} from 'angular2-busy';
import { FormGroup, FormBuilder, Validators,ReactiveFormsModule } from '#angular/forms';
import { BrowserModule } from '#angular/platform-browser';
import {MdDialog, MdDialogRef} from '#angular/material';
import {DiscardPopUpComponent} from '../../../../discard-pop-up/discard-pop-up.component';
#Component({
selector: 'app-products-form',
templateUrl: './products-form.component.html',
styleUrls: ['./products-form.component.css']
})
export class ProductsFormComponent implements OnInit, OnDestroy {
product:any = {'needTransformer':'Yes',
'power':'',
'cct':'',
'cri':'',
'lightSource':'',
'country':'',
'category':{},
'productionCompany':{},
'finish':{}};
discardPopUpTitle:string = "Discard Changes";
discardPopUpContent:string="Are you Sure you want to discard changes and exit to products table ?";
selectedPopUpOption:string;
discardDialog:DiscardPopUpComponent;
showPopUp = false;
popUpresult = false;
isFormDirty:boolean=false;
companies: string[] =[];
companiesSubscription: Subscription;
finishes: string[] = [];
finishesSubscription: Subscription;
categories: string[] = [];
categoriesSubscription: Subscription;
lightSources: string[] = [];
lightSourcesSubscription: Subscription;
countries: string[] = [];
countriesSubscription: Subscription;
routeSubscritpion: Subscription;
selectedCategory: string;
selectedFinish: string;
selectedProductionCompany: string;
selectedLightSource: string;
selectedCountry: string;
selectedTransformerNeeded: string;
isEdit: boolean = false;
isShow: boolean = false;
message: string;
#ViewChild('mainImage') mainImage: ElementRef;
#ViewChild('diemsnions') diemsnions: ElementRef;
#ViewChild('effects') effects: ElementRef;
#ViewChild('pdf') pdf: ElementRef;
#ViewChild('categoryEl') categoryEl: ElementRef;
busy: any;
isSuccess: boolean = false;
currentCode: string;
constructor(private httpService:HttpService, private adminService: AdminService, private http: Http, private route: ActivatedRoute, private router: Router,public dialog: MdDialog) {
console.log(dialog);
this.discardDialog = new DiscardPopUpComponent();
}
ngOnInit() {
// this.busy = true;
this.routeSubscritpion = this.route.params.subscribe(param => {
let code = param['code'];
if(code != undefined)
this.httpService.getProductDataByCode(code).subscribe(
(data:any)=> {
this.product=data;
this.currentCode = data.code;
this.isEdit = true;
this.selectedCategory = data.category.name;
this.selectedFinish = data.finish.name;
this.selectedCountry = data.country;
this.selectedProductionCompany = data.productionCompany.name;
this.selectedLightSource = data.lightSource;
this.selectedTransformerNeeded = data.transformerNeeded;
// this.categoryEl.nativeElement.value = data.category.name;
},
(err) => console.error(err+"<-------------"),
() => console.log('Random Quote Complete')
);
});
this.companiesSubscription = this.httpService.getAllCompanies().subscribe(
(data:any)=> {
data.forEach((entry)=> {
this.companies.push(entry.name);
});
if(this.companies.length > 0)
this.product.productionCompany = this.companies[0];
},
(err) => console.error(err+"<-------------"),
() => console.log('Random Quote Complete')
);
this.categoriesSubscription = this.httpService.getAllCategories().subscribe(
(data:any)=> {
data.forEach((entry)=> {
this.categories.push(entry.name);
});
if(this.categories.length > 0)
this.product.category = this.categories[0];
},
(err) => console.error(err+"<-------------"),
() => console.log('Random Quote Complete')
);
this.finishesSubscription = this.httpService.getAllFinishes().subscribe(
(data:any)=> {
data.forEach((entry)=> {
this.finishes.push(entry.name);
});
if(this.finishes.length > 0)
this.product.finish = this.finishes[0];
},
(err) => console.error(err+"<-------------"),
() => console.log('Random Quote Complete')
);
this.lightSourcesSubscription = this.httpService.getAllLightSources().subscribe(
(data:any)=> {
this.lightSources = data;
if(this.lightSources.length > 0)
this.product.lightSource = this.lightSources[0];
},
(err) => console.error(err+"<-------------"),
() => console.log('Random Quote Complete')
);
this.httpService.getAllCountries().subscribe(
(data:any)=> {
this.countries = data;
if(this.countries.length > 0)
this.product.country = this.countries[0];
},
(err) => console.error(err+"<-------------"),
() => console.log('Random Quote Complete')
);
}
readUrl(event,url) {
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.onload = (event) => {
var target:FileReader=<FileReader>event.target;
this.product[url] = target.result;
}
reader.readAsDataURL(event.target.files[0]);
}
}
formatStrings(str)
{
str=str.replace(/\s/g, '');
str=str.replace(/,/g, '');
str=str.toUpperCase();
return str
}
onSubmit(form:NgForm)
{
var values=form.value;
let parent=this;
let obj={
name:values.name,
description:values.description,
code:values.code,
category:{
name:values.categories
},
productionCompany:{
name:values.productionCompany
},
finish:{
name:values.finish
},
transformerNeeded:values.transformerNeeded,
power:values.power,
cct:values.cct,
cri:values.cri,
ik: values.ik,
ip: values.ip,
luminous: values.luminous,
optic: values.optic,
lightSource:values.lightSource,
country:values.productionContry,
effictImagePath:'',
normalImagePath:'',
detailsImagePath:'',
catalogPath:''
};
let headers = new Headers({ 'Content-Type': 'application/json' ,'Authorization': JSON.parse(localStorage.getItem('currentUser'))['token']});
let options = new RequestOptions({ headers: headers });
if(!this.isEdit) {
this.busy = this.http.post('http://levelskw.com/products/', JSON.stringify(obj), options).subscribe(
(data: any) => {
this.product=obj;
this.currentCode = obj.code;
this.isEdit = true;
this.selectedCategory = obj.category.name;
this.selectedFinish = obj.finish.name;
this.selectedCountry = obj.country;
this.selectedProductionCompany = obj.productionCompany.name;
this.selectedLightSource = obj.lightSource;
this.selectedTransformerNeeded = obj.transformerNeeded;
this.isSuccess = true;
this.message="Success";
parent.upload(obj.code)
},
(err) => {
this.isSuccess = false;
this.message=JSON.parse(err._body).msg;
this.isShow = true;
let timeoutId = setTimeout(() => {
this.isShow = false;
}, 5000);
},
() => console.log("")
);
} else {
this.busy = this.http.put('http://levelskw.com/products/'+this.currentCode, JSON.stringify(obj), options).subscribe(
(data: any) => {
this.isSuccess = true;
this.message="Success";
parent.upload(this.currentCode);
},
(err) =>{
this.isSuccess = false;
this.message=JSON.parse(err._body).msg;
this.isShow = true;
let timeoutId = setTimeout(() => {
this.isShow = false;
}, 5000);
},
() => console.log("")
);
}
console.log(JSON.stringify(obj));
}
ngOnDestroy() {
this.isFormDirty = false;
this.companiesSubscription.unsubscribe();
this.finishesSubscription.unsubscribe();
this.lightSourcesSubscription.unsubscribe();
}
changeFinish(finish) {
this.product.finish = finish;
console.log(this.product);
}
makeFileRequest(url:string) {
return new Promise((resolve, reject) => {
let mainImageEl: HTMLInputElement = this.mainImage.nativeElement;
let formData = new FormData();
let xhr = new XMLHttpRequest();
if (mainImageEl.files.length > 0)
formData.append("normalImagePath", mainImageEl.files.item(0), mainImageEl.files.item(0).name);
let diemsnionsEl: HTMLInputElement = this.diemsnions.nativeElement;
if (diemsnionsEl.files.length > 0)
formData.append("detailsImagePath", diemsnionsEl.files.item(0), diemsnionsEl.files.item(0).name);
let effectsEl: HTMLInputElement = this.effects.nativeElement;
if (effectsEl.files.length > 0)
formData.append("effictImagePath", effectsEl.files.item(0), effectsEl.files.item(0).name);
let pdfEl: HTMLInputElement = this.pdf.nativeElement;
if (pdfEl.files.length > 0)
formData.append("catalogPath", pdfEl.files.item(0), pdfEl.files.item(0).name);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(xhr.response);
}
}
};
xhr.open("POST", url, true);
xhr.setRequestHeader("Authorization", JSON.parse(localStorage.getItem('currentUser'))['token']);
xhr.send(formData);
});
}
upload(code: string) {
this.busy = this.makeFileRequest("http://levelskw.com/products/upload/"+code).then((result) => {
this.isShow = true;
let timeoutId = setTimeout(() => {
this.isShow = false;
}, 5000);
}, (error) => {
this.isShow = true;
let timeoutId = setTimeout(() => {
this.isShow = false;
}, 5000);
});
}
cancel() {
this.router.navigate(['/admin/products']);
}
openDialog() {
this.showPopUp=true;
this.discardDialog.show();
}
takePopUpEvent(isPopUpValueConfermed:boolean){
this.popUpresult = isPopUpValueConfermed;
if(this.popUpresult){
this.cancel() ;
}else{
this.showPopUp=false;
}
}
onChange(form:NgForm){
console.log(form);
this.isFormDirty = true;
}
}
my HTML code products-form.component.html :
<app-popup [isShow]="isShow" [message]="message" [isSuccess]="isSuccess"></app-popup>
<div [ngBusy]="busy"></div>
<div class="main-container">
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<app-discard-pop-up [showPopUp]="showPopUp" [popUpTitle]="discardPopUpTitle" [popUpContent]="discardPopUpContent" (isConfermed)="takePopUpEvent($event)" ></app-discard-pop-up>
<div fxLayout="column" fxLayoutGap="15px">
<div fxLayout="row" fxLayoutGap="29px">
<div fxLayout="column" fxLayoutGap="20px">
<div fxLayout="column" class='titleSection'>
<div class="header"><div class='header-label'>Header</div></div>
<div class='title'><input type="text" placeholder="Code" name="code" [(ngModel)]="product.code" (ngModelChange)="onChange(f)" /></div>
<div class='title'><input type="text" placeholder="Name" name="name" [(ngModel)]="product.name" (ngModelChange)="onChange(f)" /></div>
<div class="description"><textarea placeholder="Description" name="description" [(ngModel)]="product.description" (ngModelChange)="onChange(f)" ></textarea></div>
</div>
<div fxLayout="column" class="loadSection">
<div class="header"><div class='header-label'>Files</div></div>
<div fxLayout="column" class="img-section" fxLayoutGap="2px">
<div class="img-lable">Main image</div>
<div class="img-btn">
<button fxLayoutAlign="center center">Upload</button>
<img class="img-view" [src]="product.normalImagePath" />
<input type="file" (change)="readUrl($event,'normalImagePath')" #mainImage (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column" class="img-section" fxLayoutGap="2px">
<div class="img-lable">Dimensions</div>
<div class="img-btn">
<button fxLayoutAlign="center center">Upload</button>
<img class="img-view" [src]="product.detailsImagePath" />
<input type="file" (change)="readUrl($event,'detailsImagePath')" #diemsnions (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column" class="img-section" fxLayoutGap="2px">
<div class="img-lable">Effects</div>
<div class="img-btn">
<button fxLayoutAlign="center center">Upload</button>
<img class="img-view" [src]="product.effictImagePath" />
<input type="file" (change)="readUrl($event,'effictImagePath')" #effects (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column" class="img-section" fxLayoutGap="2px">
<div class="img-lable">PDF</div>
<div class="img-btn">
<button fxLayoutAlign="center center">Upload</button>
<img class="img-view" src="../../../../assets/Icons/pdf.png" />
<input type="file" #pdf (ngModelChange)="onChange(f)" />
</div>
</div>
</div>
</div>
<div fxLayout="column" class="details" fxLayoutGap="10px">
<div class="header"><div class='header-label'>Related Products</div></div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Category</div>
<select class="dropdown" name="categories" [(ngModel)]="selectedCategory" (ngModelChange)="onChange(f)" >
<option *ngFor="let category of categories" [ngValue]="category">{{category}}</option>
</select>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Manufactured By</div>
<select class="dropdown" name="productionCompany" [(ngModel)]="selectedProductionCompany" (ngModelChange)="onChange(f)" >
<option *ngFor="let company of companies" [ngValue]="company">{{company}}</option>
</select>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Materials</div>
<select class="dropdown" name="finish" [(ngModel)]="selectedFinish" (ngModelChange)="onChange(f)" >
<option *ngFor="let finish of finishes" [ngValue]="finish">{{finish}}</option>
</select>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Transformer needed</div>
<select class="dropdown" name="transformerNeeded" [(ngModel)]="selectedTransformerNeeded" (ngModelChange)="onChange(f)" >
<option value="true" selected>Yes</option>
<option value="false" >No</option>
</select>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Power(W)</div>
<input type="number" name="power" [(ngModel)]="product.power" (ngModelChange)="onChange(f)"/>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>CCT(K)</div>
<div fxLayout="row">
<input type="number" name="cct" [(ngModel)]="product.cct" #cct="ngModel" number (ngModelChange)="onChange(f)" />
<div class="validation-error-message"> <p *ngIf="cct.errors?.number" color:red> CCT should be number</p></div>
</div>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>IK</div>
<input type="number" name="ik" [(ngModel)]="product.ik" (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Index of protection</div>
<input type="number" name="ip" [(ngModel)]="product.ip" (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Luminous</div>
<input type="number" name="luminous" [(ngModel)]="product.luminous" (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Optic</div>
<input type="number" name="optic" [(ngModel)]="product.optic" (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>CRI</div>
<input type="number" name="cri" [(ngModel)]="product.cri" (ngModelChange)="onChange(f)" />
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Light Source</div>
<select class="dropdown" name="lightSource" [(ngModel)]="selectedLightSource" (ngModelChange)="onChange(f)" >
<option *ngFor="let lightSource of lightSources" [ngValue]="formatStrings(lightSource)" >{{lightSource}}</option>
</select>
</div>
</div>
<div fxLayout="column">
<div class="item-cont">
<div class='lable'>Production country</div>
<select class="dropdown" name="productionContry" [(ngModel)]="selectedCountry" (ngModelChange)="onChange(f)" >
<option *ngFor="let company of countries" [ngValue]="formatStrings(company)" >{{company}}</option>
</select>
</div>
</div>
</div>
</div>
<div class='control-btn-container'>
<div fxLayout="row" fxLayoutGap="10px">
<button class="btn cancel" fxLayoutAlign="center center" (click)="cancel()">Cancel</button>
<button type="submit" class="btn save" fxLayoutAlign="center center" >Save</button>
</div>
</div>
</div>
</form>
</div>
i use spring boot in the backend.
ERROR Error: Uncaught (in promise): Error: Runtime compiler is not loaded
Error: Runtime compiler is not loaded
at y (vendor.600ff6e….bundle.js:781)
at Z (vendor.600ff6e….bundle.js:218)
at t.compileModuleAndAllComponentsAsync (vendor.600ff6e….bundle.js:365)
at vendor.600ff6e….bundle.js:521
at t.invoke (vendor.600ff6e….bundle.js:781)
at Object.onInvoke (vendor.600ff6e….bundle.js:365)
at t.invoke (vendor.600ff6e….bundle.js:781)
at e.run (vendor.600ff6e….bundle.js:781)
at vendor.600ff6e….bundle.js:781
at t.invokeTask (vendor.600ff6e….bundle.js:781)
at Object.onInvokeTask (vendor.600ff6e….bundle.js:365)
at t.invokeTask (vendor.600ff6e….bundle.js:781)
at e.runTask (vendor.600ff6e….bundle.js:781)
at s (vendor.600ff6e….bundle.js:781)
at HTMLFormElement.invoke (vendor.600ff6e….bundle.js:781)
at y (vendor.600ff6e….bundle.js:781)
at Z (vendor.600ff6e….bundle.js:218)
at t.compileModuleAndAllComponentsAsync (vendor.600ff6e….bundle.js:365)
at vendor.600ff6e….bundle.js:521
at t.invoke (vendor.600ff6e….bundle.js:781)
at Object.onInvoke (vendor.600ff6e….bundle.js:365)
at t.invoke (vendor.600ff6e….bundle.js:781)
at e.run (vendor.600ff6e….bundle.js:781)
at vendor.600ff6e….bundle.js:781
at t.invokeTask (vendor.600ff6e….bundle.js:781)
at Object.onInvokeTask (vendor.600ff6e….bundle.js:365)
at t.invokeTask (vendor.600ff6e….bundle.js:781)
at e.runTask (vendor.600ff6e….bundle.js:781)
at s (vendor.600ff6e….bundle.js:781)
at HTMLFormElement.invoke (vendor.600ff6e….bundle.js:781)
at y (vendor.600ff6e….bundle.js:781)
at p (vendor.600ff6e….bundle.js:781)
at vendor.600ff6e….bundle.js:781
at t.invokeTask (vendor.600ff6e….bundle.js:781)
at Object.onInvokeTask (vendor.600ff6e….bundle.js:365)
at t.invokeTask (vendor.600ff6e….bundle.js:781)
at e.runTask (vendor.600ff6e….bundle.js:781)
at s (vendor.600ff6e….bundle.js:781)
at HTMLFormElement.invoke (vendor.600ff6e….bundle.js:781)
Hi i have a question about Angular 2 and really don't know how to do that and I need your help :)
I have a child component that have a simple registration form but the submit button on parent template. So when I press the submit button it will get data from child component form.
here is my example.
Parent component ts
import {Component, ViewChild, OnDestroy, Output, EventEmitter} from '#angular/core';
import {GlobalEvent} from 'app/shared/GlobalEvent';
#Component({
selector: 'signup',
templateUrl: 'SignUpModalComponent.html',
styleUrls: ['SignUpModalComponent.scss'],
})
export class SignUpModalComponent implements OnDestroy {
public overlayState: boolean;
public step: number = 1;
public formSubmit: boolean;
#ViewChild('firstModal')
modal: any;
constructor(private modalEventService: GlobalEvent) {
this.modalEventService.modalChangeEvent.subscribe((res: boolean) => {
this.overlayState = res;
if (res) {
this.modal.open();
} else {
this.modal.close();
}
});
}
closeModal(value: boolean): void {
this.modalEventService.close(false);
this.modal.close()
}
ngOnDestroy() {
this.modalEventService.modalChangeEvent.unsubscribe();
}
incrementStep():void {
this.step += 1;
}
decrementStep():void {
this.step -= 1;
}
onFormSubmit(): void {
this.formSubmit = true;
}
}
Parent component html template
<div class="modal-overlay" *ngIf="overlayState"></div>
<modal (onClose)="closeModal(false)" #firstModal >
<modal-header>
<button (click)="firstModal.close()" class="close-btn"><i class="material-icons">close</i></button>
<div class="steps-container">
<span [ngClass]="{'active': step == 1 }">1</span>
<span [ngClass]="{'active': step == 2 }">2</span>
<span [ngClass]="{'active': step == 3 }">3</span>
<span [ngClass]="{'active': step == 4 }">4</span>
</div>
</modal-header>
<modal-content>
<signup-form [hidden]="step != 1" [formSubmit]="formSubmit"></signup-form>
<signup-social ngClass="social-step{{step}}" [step]="step"></signup-social>
</modal-content>
<modal-footer>
<button md-button (click)="decrementStep()" [hidden]="step == 1"><Back</button>
<button md-button (click)="incrementStep(); onFormSubmit()" [hidden]="step != 1">Next></button>
<button md-button (click)="incrementStep()" [hidden]="step == 1 || step == 4">Skip</button>
</modal-footer>
</modal>
Child component ts file
import {Component, OnInit, Input} from '#angular/core';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
import {CustomValidators} from 'ng2-validation';
import {SignUpFormInterface} from './SignUpFormInterface';
#Component({
selector: 'signup-form',
templateUrl: 'SignUpForm.html',
styleUrls: ['SignUpForm.scss']
})
export class SignUpForm implements OnInit {
signupInfo: FormGroup;
public tmppass: any;
#Input() set formSubmit(sendData: boolean) {
if (sendData) {
}
}
constructor(private formbuilder: FormBuilder) {
}
ngOnInit() {
this.signupInfo = this.formbuilder.group({
email: ['', [CustomValidators.email]],
username: ['', [Validators.required, CustomValidators.min(10)]],
password: ['', [Validators.required, CustomValidators.rangeLength([5, 100]), this.setPass]],
confirmPassword: ['', [Validators.required, CustomValidators.rangeLength([5, 100]), CustomValidators.equal(this.tmppass)]],
fullName: ['', [Validators.required, CustomValidators.min(10)]],
gender: ['', [Validators.required]],
countrys: ['', [Validators.required]],
});
}
setPass(c: any): void {
console.log('sdsd', c.value);
if (c.value) {
this.tmppass = '';
this.tmppass = <string>c.value;
}
}
onSubmit({value, valid}: {value: SignUpFormInterface, valid: boolean}) {
console.log(this.signupInfo);
}
cons() {
console.log(this.signupInfo);
}
}
function validateEmail(c: any) {
let EMAIL_REGEXP = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
return EMAIL_REGEXP.test(c.value) ? c.email = false : c.email = true;
}
Child component html template
<div class="sign-up-form clearfix">
<form novalidate (ngSubmit)="onSubmit(signupInfo)" [formGroup]="signupInfo">
<label>
<input type="file" placeholder="Last Name*" name="lastName"/>
upload an avatar
</label>
<md-input-container>
<input md-input placeholder="Email address*" name="email" formControlName="email"/>
</md-input-container>
<!--<p *ngIf="signupInfo.controls.email.errors?.email">error message</p>-->
<div class="errror-msg" *ngIf="signupInfo.controls.email.errors?.email">
<md-hint>
<span>Name should be minimum 6 characters</span>
</md-hint>
</div>
<p *ngIf="signupInfo.controls.username.errors?.min">error message</p>
<div class="input-wrap" [ngClass]="{'error': signupInfo.controls.username.errors?.min}">
<md-input-container>
<input md-input placeholder="Username*" name="username" formControlName="username"/>
</md-input-container>
<div class="errror-msg" *ngIf="signupInfo.controls.username.errors?.min">
<md-hint>
<span>Name should be minimum 6 characters</span>
</md-hint>
</div>
<div class="errror-msg"
*ngIf="signupInfo.get('username').hasError('minlength') && signupInfo.get('username').touched">
<md-hint>
<span>Name should be minimum 6 characters</span>
</md-hint>
</div>
</div>
<p *ngIf="signupInfo.controls.password.errors?.rangeLength">error xcdfdfd</p>
<md-input-container>
<input md-input placeholder="Password*" formControlName="password"/>
</md-input-container>
<p *ngIf="signupInfo.controls.confirmPassword.errors?.rangeLength">error password</p>
<p *ngIf="signupInfo.controls.confirmPassword.errors?.equal">error equal</p>
<md-input-container>
<input md-input placeholder="Confirm Password*" formControlName="confirmPassword"/>
</md-input-container>
<p *ngIf="signupInfo.controls.fullName.errors?.min">error password</p>
<md-input-container>
<input md-input placeholder="Full Name*" name="fullName" formControlName="fullName"/>
</md-input-container>
<p *ngIf="signupInfo.controls.gender.errors?.required">error password</p>
<md-select placeholder="Gender" formControlName="gender">
<md-option *ngFor="let food of ['react','angular']" [value]="food">
{{ food }}
</md-option>
</md-select>
<p *ngIf="signupInfo.controls.countrys.errors?.required">error password</p>
<md-select placeholder="Country" formControlName="countrys">
<md-option *ngFor="let country of countrys" [value]="country">
{{ country.name }}
</md-option>
</md-select>
<div class="input-wrap">
<md-input-container placeholder="Date of Birth *">
<input md-input placeholder="mm/dd/yyyy" type="text" name="DateofBirth"/>
</md-input-container>
</div>
</form>
</div>
Thanks for help :)
I'm newbie in Angular 2 and trying to write a simple ng-form following by official tutorial.
If I'm using simple array from tutorial, it works fine:
powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];
But when I'm changing it on my custom array from http
public departments = [];
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<Object>) => this.departments = departments);
}
I'm getting an error:
error_handler.js:51 Error: Uncaught (in promise): Error: Error in ./AddClientComponent class AddClientComponent - inline template:41:12 caused by: Cannot find a differ supporting object '[object Object]' of type 'departments'. NgFor only supports binding to Iterables such as Arrays.
So where is my mistake and what am I missing? thanks in advance.
AddClientComponent
import 'rxjs/add/operator/map';
import {Component} from '#angular/core';
import {Http, Response} from '#angular/http';
import { DepartmentsComponent } from '../departments/departments.component';
#Component({
selector: 'app-add-client',
templateUrl: './add-client.component.html',
styleUrls: ['./add-client.component.css']
})
export class AddClientComponent {
public departments = [];
public firstName = '';
public lastName = '';
public id = null;
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<Object>) => this.departments = departments);
}
model = new Employee(
this.id,
this.firstName,
this.lastName,
this.departments
);
submitted = false;
onSubmit() { this.submitted = true; }
active = true;
}
export class Employee {
constructor(
public id: number,
public firstName: string,
public lastName: string,
public departments: any
) { }
}
html
<div class="container">
<div [hidden]="submitted">
<h1>Employee Form</h1>
<form *ngIf="active" (ngSubmit)="onSubmit()" #employeeForm="ngForm">
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" class="form-control" id="firstName"
required
[(ngModel)]="model.firstName"
name="firstName"
#firstName="ngModel" >
<div [hidden]="firstName.valid || firstName.pristine"
class="alert alert-danger">
First Name is required
</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" id="lastName"
required
[(ngModel)]="model.lastName"
name="lastName"
#lastName="ngModel" >
<div [hidden]="lastName.valid || lastName.pristine"
class="alert alert-danger">
Last Name is required
</div>
</div>
<div class="form-group">
<label for="departments">Department</label>
<select class="form-control" id="departments"
required
[(ngModel)]="model.departments"
name="departments"
#departments="ngModel" >
<option
*ngFor="let department of departments"
[value]="department">{{department.name}}
</option>
</select>
<div [hidden]="departments.valid || departments.pristine"
class="alert alert-danger">
Department is required
</div>
</div>
<button type="submit"
class="btn btn-default"
[disabled]="!employeeForm.form.valid">Submit
</button>
<!--<button type="button"-->
<!--class="btn btn-default"-->
<!--(click)="newHero()">New Hero-->
<!--</button>-->
</form>
</div>
<div [hidden]="!submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">First Name</div>
<div class="col-xs-9 pull-left">{{ model.firstName }}</div>
</div>
<div class="row">
<div class="col-xs-3">Last Name</div>
<div class="col-xs-9 pull-left">{{ model.lastName }}</div>
</div>
<div class="row">
<div class="col-xs-3">Department</div>
<div class="col-xs-9 pull-left">{{ model.departments }}</div>
</div>
<br>
<button class="btn btn-default" (click)="submitted=false">Edit</button>
</div>
</div>
Use a different name for
#departments="ngModel"
I think it overloads the departments property of the class used in *ngFor
Try changing type
public departments: Array<any> = [];
constructor(http: Http) {
http.get('/api/departments')
.map((res: Response) => res.json())
.subscribe((departments: Array<any>) => this.departments = departments);
}