Angular2 - pass ASYNC data to child component - javascript

I have issue, with passing async data to child component. I trying to write dynamic form generator. Issue starts when I try to call json via Observable and pass it into child component.
service:
generateSearchFields2(): Observable<any> {
return this.http
.get(this.API + 'searchFields')
.map((res:Response) => {
res.json().data as any;
for (var i = 0; i < res.json().data.length; i++) {
var searchField = res.json().data[i];
switch (searchField.component) {
case "TextboxQuestion":
let TXQ: TextboxQuestion = new TextboxQuestion({
key: searchField.key,
label: searchField.label,
value: searchField.value,
required: searchField.required,
order: searchField.order
});
this.searchFieldModels.push(TXQ);
console.log("TXQ: ", TXQ, this.searchFieldModels);
break;
case "DropdownQuestion":
let DDQ: DropdownQuestion = new DropdownQuestion({
key: searchField.key,
label: searchField.label,
required: searchField.required,
options: searchField.options,
order: searchField.order
});
this.searchFieldModels.push(DDQ);
console.log("TXQ: ", DDQ, this.searchFieldModels);
break;
default:
alert("DEFAULT");
break;
}
}
return this.searchFieldModels.sort((a, b) => a.order - b.order);
})
.catch(this.handleError);
}
Component Parent:
generateSearchFields2() {
this.service.generateSearchFields2()
.subscribe(res => this.searchFields = res)
}
Iam passing variable via INPUT directive in parent template to child: [searchFields]="searchFields"
Issue is in child component, where searchField has undefined value. In this child I pass value to another service, to create formContros, but I got undefined there also. Data missing starts here, in child:
#Input() searchFields: SearchBase<any>[] = [];
ngOnInit() {
this.form = this.qcs.toFormGroup(this.searchFields);
console.log("ONINIT DYNAMIC FORM COMPONENT: ", this.searchFields);
}
Please for hint how I can pass async variable, to not loose data meantime

You can make #Input() searchFields a setter
private _searchFields: SearchBase<any>[] = [];
#Input() set searchFields(value SearchBase<any>[]) {
if(value != null) {
this.form = this.qcs.toFormGroup(this.searchFields);
console.log("ONINIT DYNAMIC FORM COMPONENT: ", this.searchFields);
}
}
get searchFields() : SearchBase<any>[] {
return this.searchFields;
}
You can also use ngOnChanges() which is called every time an input is updated, but a setter is usually more convenient except perhaps when the executed code depends on multiple inputs being set.

In the ngOnInit event the data which comes from the parent is not bound yet. So your searchFields is undefined yet. You can use it in NgAfterViewInit component lifecycle event.
#Input() searchFields: SearchBase<any>[] = [];
ngAfterViewInit() {
this.form = this.qcs.toFormGroup(this.searchFields);
console.log("ONINIT DYNAMIC FORM COMPONENT: ", this.searchFields);
}
For other cases you can see Angular2 Component Lifecycle events

Related

No reactivity between service and component

I take out the logic in the service separately from the component.
There is a property in the logic, on which the display of the element in the component depends
The property is declared like this:
function serviceAbonent () {
...
const switchAdd = ref(false)
...
return { switchAdd }
}
In the component, I get this property like this:
const { stitchAdd }= serviceAbonent()
In this method, I call the service method, which changes the value of the property
function newItemAdd () {
serviceAbonent().add(newItemBlack, 'Black', 'CreateDate')
}
service method:
async function add (newItem :any, list: string, defaultSort: string) {
switchAdd.value = false ...
The problem is that when the value changes, the value only changes in the service, but does not change in the component. Why is that ?

Cannot read property 'charAt' of undefined Get #input

I'm trying to pass my Get method from my parent component to my child component to display the data but I get an error I don't understand.
the error comes from my service
here is the error Cannot read property 'charAt' of undefined
thanks in advance.
parent.component.html
<app-child [arrayList]="getDetails()"></app-child>
parents.component.ts
public array: any[] = [];
getRoute() {
this.route.paramMap.subscribe((params: Param) => {
this.id = params.get('id');
this.material = params.get('matos');
}
}
getDetails() {
this.service.get(this.id, this.material).subscribe((data:any[]) => {
this.array.push(data);
}
}
parent.service
get(id: string, material:string) {
let material = this.str(material:string);*
return this.get<any>(url+id+material);
str(material) {
return material.charAt(0).toUpperCase()+material.substr(1);
}
child.component.ts
#Input() arrayList: any[] = [];
There are several glitches in your code, first in child component add input decorator, so that it accepts the input i.e
child.component.ts
#Input() arrayList: any;
parents.component.html
In parents component you are passing getDetails() method to input which will always be undefined since its not returning anything, try to pass array list in which you are pushing the data
<app-child [arrayList]="array"></app-child>

Retrieve the data from one component to another

We are trying to use the NavigationExtras to pass data from one component to another (one page to another) like below
viewProjectDetails(e) {
const navigationExtras: NavigationExtras = {
state: {
ProjectInfo: e.data,
UserSelection: this.UserSelection
}
};
this.router.navigate(['dashboard/ProjectShipment'], navigationExtras);
}
I am trying to get the ProjectInfo and UserSelection array in to the another component
projDetail : any;
userSelection: any;
getPrjDetails() {
const navigation = this.activatedRoute.getCurrentNavigation();
const state = navigation.extras.state as {
}
Listen to the queryParams and catch the NavigationExtras
this.route.queryParams.subscribe(params => {
console.log(params["state"]);
});
constructor(private router: Router) {
console.log(this.router.getCurrentNavigation().extras.state.Projectinfo);
// should log e.data
}
You need to call getCurrentNavigation() method inside of the constructor, elsewhere the navigation has finished.

Pass first item of subscribed data to service

I am developing angular application where I need apply following mechanism:
My view has 2 parts (list of items and detail if selected item). User can click on some item, and next service fetch additional data for that item and show them in detail view. Also I want select first item automatically on start if is available.
Here is my service:
#Injectable()
export class ItemService {
private url: string;
private itemSource = new BehaviorSubject<Item>(null);
selectedItem = this.itemSource.asObservable();
constructor(private http: HttpClient) {
this.url = 'http://localhost:8080/api/item';
}
getItems(): Observable<Item[]> {
let observable = this.http.get<Item[]>(this.url)
.map(items => items.map(item => {
return new Item(item);
}));
return observable;
}
selectItem(item: Item) {
return this.http.get<Item>(this.url + '/' + item.id)
.map(item => new Item(item))
.subscribe(t => this.itemSource.next(t));
}
}
in detail component I am subscribing selected item like this:
ngOnInit() {
this.itemService.selectedItem.subscribe(item => this.selectedItem = item);
}
and following code is from my component where I displayed list of items. I also want set selected item after data are subscribed but my code isn't works. I am iterating items[] property in html template and data are showed, but when I access to this array after I subscribed data I got undefined. Can you please fix my code? Thanks!
public items = [];
constructor(private itemService: ItemService) { }
ngOnInit() {
this.itemService.getItems()
.subscribe(
data => this.items = data,
err => console.log(err),
function () {
console.log('selected data', this.items); // this prints undefined
if (this.items && this.items.length) {
this.itemService.selectedItem(this.items[0])
}
});
}
Your problem is that you are not using an arrow function for the complete callback in your call to subscribe. As you see, you are using arrow functions for next and error.
When you define a new function with function(...) {...} you're creating a new context, and so the this keyword changes its meaning. The difference between arrow function and normal functions (besides being more elegant, in my opinion), is that arrow functions do not define a new context for this, and so the meaning of that keyword is the same as in the context they are defined. So, in your next and error callbacks, this is your component, but in your call to complete, this is, most surely, a reference to window, which does not have an items property, hence the undefined.
Change your code to:
public items = [];
constructor(private itemService: ItemService) { }
ngOnInit() {
this.itemService.getItems()
.subscribe(
data => this.items = data,
err => console.log(err),
() => {
console.log('selected data', this.items); // this prints undefined
if (this.items && this.items.length) {
this.itemService.selectedItem(this.items[0])
}
});
}
I imagine you used the function keyword there because that function had not arguments, but you can express that with the syntax () => expression, or () => {...}
data => this.items = data, after all, is a simpler and more elegant way of writing
(data) => { return this.items = data; }

set and get data from service angular 5

I am using angular 5
my scenario is from one component im setting the data in service and from another component i'm getting that data|
Component- 1:
makeUser(row){
this.agentsService.setSelectedAgentData(row); // setting the data (row) in agentsService.
const mrf = this.modalService.open(MakeUserComponent);
}
Service:
declaring the varible in class.
public selectedData:any = {};
setter and getter methods are as below
setSelectedAgentData(selectedTableRowData){
this.selectedData = selectedTableRowData;
}
getSelectedAgentData(){
return this.selectedData;
}
Component - 2:
ngOnInit() {
this.userDetails = this.agentsService.getSelectedAgentData();
this.roles = this.agentsService.getRolesList();
}
Here the selectedData value is an empty object when I call the method this.agentsService.getSelectedAgentData() from component -2
Any help would be appreciated.
You can use Subject (rxjs library) for this purpose. So Subject can generate data on the one hand. And on the other hand, you can subscribe to changes in any place.
You service would look like this:
#Injectable()
export class YourService {
public selectedData: Subject<any>;
constructor() {
this.selectedData = new Subject();
}
generateSelectedAgentData(row: string) {
this.selectedData.next(row);
}
}
In your first Component:
makeUser(row){
this.agentsService.generateSelectedAgentData(row);
const mrf = this.modalService.open(MakeUserComponent);
}
In your second Component:
constructor(private ys: YourService){
this.ys.selectedData.subscribe(
data => {
console.log(data);
this.userDetails = data;
});
}

Categories