I have one service in which I have setup a stream.
import {Injectable} from '#angular/core'
import {Subject} from 'rxjs/Subject';
import { Column } from './../../column.model';
#Injectable()
export class ColumnService {
selectedColumnInstance:Column = new Column();
// Observable selectColumn source
private selectColumnSource = new Subject<Column>();
// Observable selectColumn stream
selectColumn$ = this.selectColumnSource.asObservable();
// service command
selectColumn(column:Column) {
console.log(column);
this.selectedColumnInstance=column;
this.selectColumnSource.next(column);
}
}
I am updating this stream as:
this.rapidColumnService.selectColumn(this.selectedCol); //selectedCol is new value
Now I have a component which loads its childComponent if this columnStream is having any value:
designer.component.html
<div class="col-md-3" *ngIf="selectedComponent">
<editor component-name="value-editor" [(model)]="selectedComponent.model"></editor>
</div>
Now Inside my designer.component.ts, I have subscribed to this stream inside ngOnInit() lifecycle hook.
ngOnInit() {
this.subscriptionColumn = this.rapidColumnService.selectColumn$.subscribe(
selectedComponent => {
this.selectedComponent = selectedComponent;
});
}
So far so good, If I am in designerComponent , then every time I am updating column in service , the view changes.
But as soon as I redirect to other component and redirect to designer again I am not able to load the editor component.
I can see the stream getting updated in service.
I want to load editor-component every time stream gets updated.
is it the router issue?
any inputs?
thanks & regards.
Related
I've got a component A, which sends a value to a service method (via calling it), and then I tried to create a subject and 'observe' it from component B, thus triggering an action on component B from component A.
This is what I did:
Component A sends the data:
this.service.method(id_estado)
Which is recieved by service:
import { Injectable } from '#angular/core';
import { BehaviorSubject, of, Observable, Subscription, Subject } from 'rxjs';
export class service {
estado: any;
subject = new Subject<any>();
constructor( private api: ApiService ) {
}
service ( id_estado ){
let subject = new Subject<any>();
this.subject.next(estado)
}
}
And in component B I'm trying to observe it like this:
this.service.subject.subscribe( (data) => {
console.log(data);
});
Component B's part takes place inside a method. Is this the cause of the problem? I can't get any data to show on my console.log
let subject = new Subject<any>();
this.subject.next(estado)
- should be moved to constructor to be initialized.
or just execute service in constructor:
import { Injectable } from '#angular/core';
import { BehaviorSubject, of, Observable, Subscription, Subject } from 'rxjs';
export class service {
estado: any;
subject = new Subject<any>();
constructor( private api: ApiService ) {
service(true); // or some value you need.
}
service (id_estado){
this.subject.next(estado);
}
}
In this case you can remove initialization subject = new Subject<any>(); before constructor.
In your case you've just got Subject, but .next() wasn't executed.
Component B's part takes place inside a method. Is this the cause of
the problem?
Yes, that's the problem. If that method isn't called, then you aren't subscribing to the Subject and that is why no data is received.
Move this subscribing part to ngOnInit of Component B.
Also in the service, you are creating a new Subject whenever that method is called.
Subject is already defined at the beginning, no need to do it again.
After this change, your service should look like:
export class service {
estado: any;
subject = new Subject<any>();
constructor( private api: ApiService ) {
}
service(id_estado) {
this.subject.next(estado);
}
}
Check out this StackBlitz where you can see components communicating in real time using Subject.
you should try event emitter service of angular, in which you subscribe your data in pass that data value in any component using event emitter service.
Am working on a Single page Application built using Angular 8 on the frontend and Laravel on the backend. It is a CRUD application, on the delete functionality, it is working well by deleting the user of the specific id on the database. After the user of the specific id is deleted, am fetching all the products from the database but I want to update the data on the U.I afresh with the new data (excluding the deleted resource).
Kindly assist?
Show.component.ts file
import { Component, OnInit , ViewChild, ElementRef} from '#angular/core';
import { SharedService } from 'src/app/Services/shared.service';
import { AuthService } from 'src/app/Services/auth.service';
import { Router } from '#angular/router';
import { Observable } from 'rxjs';
import { SnotifyService } from 'ng-snotify';
#Component({
selector: 'app-show',
templateUrl: './show.component.html',
styleUrls: ['./show.component.css']
})
export class ShowComponent implements OnInit {
public userData : any[];
public error = null;
constructor(
private Shared : SharedService,
private Auth:AuthService,
private router: Router,
private Notify:SnotifyService
) { }
//Update the data when the DOM loads
ngOnInit() {
this.Shared.checkAll$.subscribe(message => this.userData = message);
}
//Method called when the delete button is triggered from the html
//Inside it we submit the data to the backend via a service and get
//the response
deleteUser(id:number){
return this.Auth.delete(id).subscribe(
data => this.handleDeleteResponse(data),
error => this.handleDeleteError(error)
);
}
//data below contains data from the backend after successful deletion
handleDeleteResponse(data:any){
this.Notify.success(`Successfully Deleted in our records`, {timeout:4000});
}
handleDeleteError(error:any){
console.log(error);
}
}
In you’re handleDeleteResponse method, there is a data if the data is the userData this.userData = data or it’s simple delete the user id from the array in you’re Js in the subscription of your delete method.
Like:
this.userData = this.userData.filter(user => user.id !== idToDelete )
Method 1:
Define a Subject in your service and subscribe to that subject in the service to receive the data. In the component, change the lifecycle hook to 'onChanges'. As soon as the data in the Subject is received/updated (with the deleted records) ngChanges shall reflect it in the DOM.
Method 2:
Track the records on the front-end in the form of list and when the service gives the response of delete as success then delete that very record in the list using ID or any other unique identifier. In this case you need not to populate all the records again.
export class MyComponent implements OnInit, OnChanges {
ngOnChanges() {
// code here
}
ngOnInit() {
// code here
}
}
Searched for a solution in other questions but nothing helped me..
I wish to redirect to url like,
this.router.navigateByUrl('/products');
In which i need to pass the array and need to get it it in the component which has the active link products using skip location change without showing anything in url.
Array will be like,
products = [{"id":1,"name":"Product One","id":2,"name":"Product Three","id":3,"name":"Product Six"}]
I need to pass this entire array in router link and need to retrieve it in another component (products) active link using skipLocation Change true..
Tried with sharedService but i am getting issue of data loading at right point of time and hence i decided to use via router link..
If this is not a good approach, kindly suggest other alternative without using sharedservice..
You can use Angular Services for a large data.
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class ExampleService {
private subject = new Subject<any>();
updateRouteData(data) {
this.subject.next(data);
}
routeData(): Observable<any> {
return this.subject.asObservable();
}
}
In your components;
For set route data;
import { ExampleService } from '/example.service'
export class ComponentOne{
constructor(private exampleService:ExampleService){
this.exampleService.updateRouteData(data)
}
You can pass data like;
import { ExampleService } from '/example.service'
export class ComponentTwo{
constructor(private exampleService:ExampleService){
this.exampleService.routeData().subscribe(data => {
console.log(data)
})
}
I'm using Angular Material Data Table in my project. The table is rendering with data
My problem is that I can't update automatically the view when I add new data to the database, every time I should refresh my page.
According to Cdk-table and after reading this tutorial I tried to add live data streaming that to table:
Here's my logique :
import { Component, OnInit } from "#angular/core";
import { MatTableDataSource } from "#angular/material";
import { AjoutprojService } from "../ajoutproj.service";
import { NouveauProjet } from "../models/nouveau-projet";
import { Observable } from "rxjs/Observable";
import 'rxjs/add/observable/merge';
import { DataSource } from "#angular/cdk/collections";
#Component({
selector: "app-liste-projets",
templateUrl: "./liste-projets.component.html",
styleUrls: ["./liste-projets.component.css"]
})
export class ListeProjetsComponent implements OnInit {
constructor( private ajoutProj: AjoutprojService ) {}
nouveauProjet: NouveauProjet[];
nouveauProjet2: NouveauProjet[];
stateExression: string = "inactive";
ngOnInit() {}
displayedColumns = ["Nom projet", "Lead Projet", "effectif"];
dataSource = new UserDataSource(this.ajoutProj);
applyFilter(filterValue: string) {
filterValue = filterValue.trim(); // Remove whitespace
filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches
//this.dataSource.filter = filterValue;
}
}
export class UserDataSource extends DataSource<any> {
constructor(private ajoutProj: AjoutprojService) {
super();
}
/*returns an observable that emits an array of data.
Whenever the data source emits data to this stream, the table will render an update.*/
connect(): Observable<NouveauProjet[]> {
return this.ajoutProj.getAllProj();
}
disconnect() {}
}
Here's my service
getAllProj(): Observable<NouveauProjet[]> {
return this.http.get<NouveauProjet[]>(
"http://127.0.0.1:8081/api/proj/projets"
);
}
ajoutProj.getAllProj() service is getting right data. but view is not live updating.
HttpClient doesn't stream. You're getting your data only once.
First you'd need a realtime database / backend solution, then you need to connect to that via websocket and listen to changes in the database.
Some frameworks / libraries that I like and package both the client- and serverside of the equation, and make the whole thing a lot easier:
Fireloop - built on top of Loopback 3 on nodejs, provides Angular SDK creation, ie. same models and APIs on client as on server. Typescript, Observables all the way. It's just awesome.
Firebase - "backendless", totally different way of thinking about a "server" from any REST scheme you might be used to.
Meteor - a monolithic framework, probably also very far from what you're used to.
Of course there's always another (very inefficient) way: Poll your DB every X seconds for changes.
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/switchMap';
export class UserDataSource extends DataSource<any> {
constructor(private ajoutProj: AjoutprojService) {
super();
}
connect(): Observable<NouveauProjet[]> {
const initialDelay = 0; // Time to wait before first poll, after the table has connected to this DataSource
const period = 10000; // Polling period in milliseconds
return Observable.timer(initialDelay, period)
.switchMap(() => this.ajoutProj.getAllProj());
}
disconnect() {}
}
SERVICE--
import {Injectable} from '#angular/core';
import {UserData} from '../user-data/user-data.component';
#Injectable()
export class UserDataService {
constructor(){}
userdata:UserData[];
getData(){
console.log('service',this.userdata);
return this.userdata;
}
setData(user:any){
this.userdata=user;
console.log(this.userdata);
}
}
USER-DATA-class ---
export class UserData {
firstname: string;
middlename: string;
lastname: string;
email: string;
contact: number;
}
Component1 --
import { Component,OnInit,OnDestroy } from '#angular/core';
import { UserData } from '../../user-data/user-data.component';
import { ViewEditUser } from '../../view-edit-user/view-edit-user.component';
import {UserDataService} from '../../user-data-service/user-data-service.service';
#Component({
selector: 'form-page',
templateUrl: `app/add-user-sidebar/user-form/form.component.html`,
providers:[UserDataService]
})
export class Form implements OnInit,OnDestroy {
userdetail:UserData;
constructor(private service:UserDataService){
}
addUser(first:string,middle:string,last:string,emailid:string,contactno:number){
this.userdetail=({firstname:first,middlename:middle,lastname:last,email:emailid,contact:contactno})
console.log(this.userdetail);
this.service.setData(this.userdetail);
}
ngOnInit(){
}
ngOnDestroy(){
}
}
Component2--
import { Component,Input, OnInit } from '#angular/core';
import { Form } from '../add-user-sidebar/user-form/form.component';
import {UserData} from '../user-data/user-data.component';
import { WelcomePage } from '../welcome-page/welcome-page.component';
import {UserDataService} from '../user-data-service/user-data-service.service';
#Component({
selector:'view-edit',
templateUrl: 'app/view-edit-user/view-edit-user.component.html',
providers: [UserDataService]
})
export class ViewEditUser implements OnInit {
arraydata:any;
constructor(private service:UserDataService){}
// arraydata:any;
printarray(){
console.log(this.arraydata);
}
ngOnInit()
{
this.arraydata=this.service.getData();
console.log("hhghdfghdf",this.arraydata);
}
}
I am new to angular2, I have two components in my module, one component is a form where user inputs data, that data is then sent to a service, when I console.log it then I can see the data in service. but when I try to access that array from the second component then I can't access the data what to do?
If you provide the service on each component, you can't use it for communication, because each component will get a different service instance.
If one component is a parent (ancestor) of the other component, only provide it on the parent component.
Otherwise provide it on a component that is a parent (anjestor) of both or provide it only in #NgModule() to make the service global.
You also need to be aware that it's possible that one component reads, before the other set the value, depending on where you set the value and in what order the components are created.
Using a BehaviorSubject usually avoids this pitfall, because this way it doesn't matter which component is created first or if one component tries to read, while the other hasn't set the value yet.
For shareing between to Angular instances see also How to share service between two modules - #NgModule in angular2?
You nee to use observables to pass data between components.
In your service create a Subject type variable and in the your first component do a .next to pass data to the service and in your 2nd component, subscribe to the service veriable and it will get you the data.
You are not getting the data because of the async behavior of JavaScript which will be handled by observables