I'm having issues with errors regarding `#Output` and `#EventEmitter` in Angular7.
<button (click)="updateStatus()" class="btn btn-primary" >Valider</button>
Code handling the click-event in the component:
import { Component, OnInit, Input, Output, EventEmitter, OnChanges } from '#angular/core';
#Input()
set selectedCommande(value: Command) {
this._selectedCommande = value;
}
get selectedCommande(): Command {
return this._selectedCommande;
}
//this catch the value in the first time , but after it fails
#Output() putSelectedCommand = new EventEmitter();
updateStatus() {
this.putSelectedCommand.emit(this._selectedCommande);
}
Error:
>TypeError: this.putSelectedCommand.emit is not a function
Related
How can we share data between two components - both are completely separate components? (which are not in a child-parent relationship)
I want to show my registration component's variable 'totalReg' value in my header component. Both files are below.
This is my reg.component.ts
import { Component, Output } from '#angular/core';
import { UserService } from '../services/reg.service';
import { VERSION } from '#angular/core';
#Component({
templateUrl: 'reg.component.html'
})
export class RegComponent {
constructor(
private userService: UserService,
) { }
#Output() totalReg: any;
register(event: any) {
this.userService.create(event.target.username.value)
.subscribe(
data => {
this.totalReg = data['data'].userId;
console.log(this.totalReg); // Navigate to the
listing aftr registration done successfully
},
error => {
console.log(error);
});
}
}
This is my header.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
This is html of my header component header.component.html
<div class="container">
<mat-toolbar>
<ul class="nav navbar-nav">
<li><a [routerLink]="['/login']">Login</a></li>
<li><a [routerLink]="['/reg']">Registration</a>
</li>
<li><a [routerLink]="['/users']">All Users</a>
</li>
</ul>
</mat-toolbar>
<span>{{totalReg}}</span>
</div>
header component should show the value of totalReg .
you can do this with help of service class.
you are already using the UserService in RegComponent , so use the same service in the HeaderComponent to get the data.
HeaderComponent.ts
export class HeaderComponent implements OnInit {
totalReg: any;
constructor(private service : UserService) { }
ngOnInit() {
this.totalReg = this.service.totalRg;
}
}
RegComponent.ts
export class RegComponent {
#Output() totalReg: any;
constructor(private userService: UserService) { }
register(event: any) {
this.userService.create(event.target.username.value)
.subscribe(data => {
this.totalReg = data['data'].userId;
console.log(this.totalReg); // Navigate to the listing aftr registration done successfully
this.service.totalRg = this.totalReg;
},
error => {
console.log(error);
});
}
}
you are already using a class in service class you need add the variable as totalRg
UserService.ts
export class UserService {
totalRg:any;
constructor() { }
create(name: any) {
return ....//
}
}
I am new to angular 7 and didn't find any proper answer for similar questions posted.
I am getting Property 'subscribe' does not exist on type 'void' in angular-cli. I tried importing subscribe from rxjs but didn't find that library.
The problem is in the UpdateRecord Function!
product.component.ts code:
the code bellow is exist in compoent.ts of product
import { Component, OnInit } from '#angular/core';
import { ProductService } from 'src/app/shared/product.service';
import { NgForm } from '#angular/forms';
import { ToastrService } from 'ngx-toastr';
import { filter, map } from 'rxjs/operators';
#Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
constructor(private service : ProductService, private toastr : ToastrService) { }
ngOnInit() {
this.resetForm();
}
resetForm(form?: NgForm) {
if (form != null)
form.resetForm();
this.service.formData = {
ProductID: null,
ProductName: '',
ProductDescription: '',
Price: 0.00,
Image: '',
Qte: null
}
}
onSubmit(form: NgForm) {
if (form.value.ProductID == null)
this.insertRecord(form);
else
this.updateRecord(form);
}
insertRecord(form: NgForm) {
this.service.postProduct(form.value).subscribe(res => {
this.toastr.success('Inserted successfully', 'Product. Register');
this.resetForm(form);
this.service.refreshList();
});
}
updateRecord(form: NgForm) {
this.service.putProduct(form.value).subscribe(res => {
this.toastr.success('Updated successfully', 'Product. Update');
this.resetForm(form);
this.service.refreshList();
});
}
}
product.service.ts code :
the code bellow is exist in service file related to product
import { Injectable } from '#angular/core';
import { Product } from './product.model';
import { HttpClient } from "#angular/common/http";
#Injectable({
providedIn: 'root'
})
export class ProductService {
formData : Product
list : Product[]
readonly rootURL= 'http://localhost:50369/api'
constructor(private http : HttpClient) { }
postProduct(formData : Product){
return this.http.post(this.rootURL+'/Product', formData);
}
refreshList(){
return this.http.get(this.rootURL+'/Product')
.toPromise().then(res => this.list = res as Product[]);
}
putProduct(formData : Product){
this.http.put(this.rootURL+'/Product/'+formData.ProductID,FormData);
}
}
Thanks in advance,
I missed return :
So in putProduct function in product.service.ts is updated to be :
putProduct(formData : Product){
return this.http.put(this.rootURL+'/Product/'+formData.ProductID,FormData);
}
And it's working now!
Your HttpClient.put function seems to be incorrectly used (you are passing the class as parameter when you should be passing the object).
Look for the function updateHero() in this StackBlitz example.
/** PUT: update the hero on the server. Returns the updated hero upon success. */
updateHero (hero: Hero): Observable<Hero> {
httpOptions.headers =
httpOptions.headers.set('Authorization', 'my-new-auth-token');
return this.http.put<Hero>(this.heroesUrl, hero, httpOptions)
.pipe(
catchError(this.handleError('updateHero', hero))
);
}
Taking again the tutorial of the site Angular, I created in winamp a database with a table including a field {"id": id, "name": name} and I make 2 queries on this table with Symfony4:
1) A request to list heroes.
2) A request to create hero.
Executed from Angular 7, the query 1) works perfectly (route / listerHeroes).
Executed from Angular 7, query 2) does not work, it returns error 405 (route / ajouterHero). However launched from Postman, this query works.
I can not find any documentation to explain to me this bug on which I stumble for several days. A track please
Below copy of both classes: heroes.service.ts and component3.component.ts
// heroes.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { HttpErrorHandler, HandleError } from './http-error-handler.service';
import { Hero } from '../assets/Structure';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
#Injectable({ providedIn: 'root' })
export class HeroesService {
heroesUrl = 'http://heroes/';
private handleError: HandleError;
constructor(private http: HttpClient, httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('HeroesService');
}
getHeroes$(): Observable<Hero[]> {
return this.http.get<Hero[]>(`${this.heroesUrl}listerHeroes`, httpOptions);
}
addHero(hero: Hero): Observable<Hero> {
return this.http
.post<Hero>(`${this.heroesUrl}ajouterHero`, hero, httpOptions)
.pipe(catchError(this.handleError('addHero', hero)));
}
}
// component3.component.ts
import { Component, OnInit } from '#angular/core';
import { HeroesService } from '../heroes.service';
import { Hero } from '../../assets/Structure';
#Component({
selector: 'app-component3',
templateUrl: './component3.component.html',
styleUrls: ['./component3.component.css']
})
export class Component3Component implements OnInit {
heroes: Hero[];
editHero: Hero;
constructor(private heroesService: HeroesService) {}
ngOnInit() {
this.heroesService.getHeroes$().subscribe(res => (this.heroes = res));
}
addHero(name: string): void {
name = name.trim();
console.log('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF C3A name =', name);
if (!name) {
return;
}
const newHero: Hero = { 'id': 0, 'name': name } as Hero;
this.heroesService.addHero(newHero).subscribe(hero => {
console.log('GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG C3B hero= ', hero);
this.heroes.push(hero);
});
}
}
I found the solution:
The blocking was listed backend (Symfony4) which refused the pre-query OPTIONS. It was necessary to install and configure the bundle nelmio (https://github.com/nelmio/NelmioApiDocBundle) which allows the smooth running of the request.
I have a snackbar component which I have created like this!
import {Component, ViewEncapsulation, OnInit, OnDestroy} from '#angular/core';
import {
MatSnackBar,
MatSnackBarConfig,
MatSnackBarHorizontalPosition,
MatSnackBarVerticalPosition,
} from '#angular/material';
import { Subscription } from 'rxjs';
import { AuthenticationService } from "../../services/authentication.service";
#Component({
selector: 'snack-message',
templateUrl: './messages.component.html',
styleUrls: [ './mesaages.component.scss' ],
encapsulation: ViewEncapsulation.None
})
export class SnackBarMessages implements OnInit, OnDestroy {
action: boolean = true;
setAutoHide: boolean = true;
autoHide: number = 2000;
horizontalPosition: MatSnackBarHorizontalPosition = 'center';
verticalPosition: MatSnackBarVerticalPosition = 'bottom';
private showMessageSub: Subscription;
messageData: object;
addExtraClass: boolean = false;
constructor(public snackBar: MatSnackBar, public authenticationService: AuthenticationService) {
}
ngOnInit() {
this.messageData = this.authenticationService.getMessageData();
this.showMessageSub = this.authenticationService.getMessageListener()
.subscribe(data => {
this.messageData = data;
});
this.openMessageSnackBar(this.messageData);
}
openMessageSnackBar(data) {
let config = new MatSnackBarConfig();
config.verticalPosition = this.verticalPosition;
config.horizontalPosition = this.horizontalPosition;
config.duration = this.setAutoHide ? this.autoHide : 0;
this.snackBar.open(data.message, data.action, config);
}
ngOnDestroy() {
if (this.showMessageSub) {
this.showMessageSub.unsubscribe();
}
}
}
I have added subject and i have created a subscription which listens to the messageListener in my Authentication Service. Then i call next with my subjectListener with the data I want to pass. I am not getting any call on my component. I don't understand why ? This is my Service!
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Subject } from 'rxjs';
import { Router, ActivatedRoute } from '../../../node_modules/#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
private mesageListener = new Subject<object>();
private messageData: object;
getMessageListener() {
return this.mesageListener.asObservable();
}
getMessageData() {
return this.messageData;
}
createUser(email: string, password: string) {
const userData: AuthModel = {
email: email,
password: password
}
const requestPath = this.getModes()[`${this.navigatedFrom}`];
this.http.post(`http://localhost:3000/api/${requestPath}/signup`,userData)
.subscribe(response => {
this.messageData = {
message: 'Sign Up Successful. Please Login now!',
action: 'Ok! Got it.'
}
this.mesageListener.next(this.messageData);
});
}
}
Try to use new BehaviorSubject<object>(null); for mesageListener .
you can see more details on Subject and BehavoiurSubject here : angular2-difference-between-a-behavior-subject-and-an-observable/
In Component subscribe to the value of Observable. It should work.
I've been working on something that uses a shared dart package through for firestore and come across an interesting issue.
I have a business logic object that is basically as follows:
class HomeBloc {
final Firestore _firestore;
CollectionReference _ref;
HomeBloc(this._firestore) {
_ref = _firestore.collection('test');
}
Stream<List<TestModel>> get results {
return _ref.onSnapshot.asyncMap((snapshot) {
return snapshot.docs.map((ds) => TestModel(ds.get('data') as String)).toList();
}
}
}
Given the following code component:
#Component(
selector: 'my-app',
templateUrl: 'app_component.html',
directives: [coreDirectives],
pipes: [commonPipes]
)
class AppComponent extends OnInit {
HomeBloc bloc;
Stream<List<TestModel>> results;
AppComponent() {
}
#override
void ngOnInit() {
print("Initializing component");
fb.initializeApp(
//...
);
getData();
}
Future<void> getData() async {
final store = fb.firestore();
bloc = HomeBloc(store);
}
}
I would expect the following to work, but it does not:
<div *ngIf="bloc != null">
<h2>Loaded properly</h2>
<ul>
<li *ngFor="let item of bloc.results | async">
{{item.data}}
</li>
</ul>
</div>
However, if I instead change getData and the html to the following:
Future<void> getData() async {
final store = fb.firestore();
bloc = HomeBloc(store);
results = bloc.results;
}
// HTML
<ul *ngFor="let item of results | async">
Everything works as expected. What's going on here?
The answer is that the get method is creating a new list every time its accessed, which isn't giving Angular an oppotunity to render the items before resetting. The correct implementation of HomeBloc:
class HomeBloc {
final Firestore _firestore;
CollectionReference _ref;
HomeBloc(this._firestore) {
_ref = _firestore.collection('test');
_results = _ref.onSnapshot.asyncMap((snapshot) {
return snapshot.docs.map((ds) => TestModel(ds.get('data') as String)).toList();
}
Stream<List<TestModel>> _results;
Stream<List<TestModel>> get results => _results;
}