Angular array works in console but not in dom - javascript

thank You for reading. I'm a Angular beginner and have an first problem I can't solve. I read many, many posts without success, sorry.
My seach form is working fine if I get the search phrase in one component and process it in another component. The *ngFor loop gives back the right result-array in dom and console: searchCustomer(phrase).
The exactly same search function works not, if I include a header component with another search form - although I get the right results via console(!). I included the header via app-header in component.html.
Why contains the array "results" the right items but the dom isn't showing it? This is my code:
search.component.html:
<form #f = "ngForm" action="verification" method="get">
<input [(ngModel)] = "phrase" type="text" name="phrase">
<button type="button" (click)="searchCustomer()">Search</button>
</form>
search.component.ts:
searchCustomer() {
this.dataService.setPhrase(this.phrase); // store phrase
this.router.navigate(['/results']); // navigate
}
result.component.html:
<app-header></app-header>
<div class="col-md-6" *ngFor="let vs of results">
...
</div>
result.component.ts:
import { ChangeDetectorRef, Component, OnInit } from '#angular/core';
// add ApiService
import { ApiService } from '../~services/api.service'; // ApiService
// add customers Model
import { Customer } from '../~interfaces/customers';
// DataService
import { DataService } from "../~services/data.service";
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css'],
})
export class ResultComponent implements OnInit {
// add array:
results: Customer[];
// add variable
phrase: string;
constructor(
private apiService: ApiService,
private dataService: DataService,
private cdr: ChangeDetectorRef
) {
}
ngOnInit() {
}
searchCustomer(phrase) {
// search
this.apiService.searchCustomer(phrase).subscribe((result:Customer[]) => {
this.results = result;
console.log(this.results);
this.cdr.detectChanges();
}
)
}
}
header.component.html:
<form #f = "ngForm">
<input type="text" [(ngModel)] = "phrase" type="text" value="{{phrase}}">
<button type="button" (click)="searchCustomer()">Search</button>
</form>
header.component.html:
searchCustomer(){
this.dataService.setPhrase(this.phrase);
this.resultComponent.searchCustomer(this.phrase);
}
If I start the search from Header, I can see the correct array "results" in Console, but not in dom. There is no refreshing.
Thank you for eye-opening,
Matthias

This was the solution in result.component.ts
responsePage$: Observable<ResponsePage>;
ngOnInit() {
this.apiService.searchCustomer(phrase).subscribe((result:Customer[]) => {
this.results = result;
this.searchCustomer(phrase);
});}
searchCustomer(phrase) {
this.responsePage$=this.apiService.customers(phrase);
}

Related

How to update parent component view when data is fetched from child component?

I have a parent and a child component, the child component is actually a modal where we can enter emails and click on 'Add to List'.
The entered emails are then fetched from parent component using #ViewChild property. The array details are obtained in parent because I can console.log() and see them from parent.
But how do I update a part of view in Parent with this new data is received ?
The code and explanations are as below :
Child component :
"emails" is an array with email ids.
I am fetching this array from child.
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'app-add-student-popup',
templateUrl: './add-student-popup.component.html',
styleUrls: ['./add-student-popup.component.scss']
})
export class AddStudentPopupComponent implements OnInit {
emails: string[] = [];
constructor() { }
ngOnInit(): void {
}
**** Some other code that adds user entered emails to an array 'emails' ****
----
----
sendData() {
console.log(this.emails);
}
}
Parent
import { AfterViewInit, Component, OnInit, ViewChild } from '#angular/core';
// Add students modal popup
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal/';
import { AddStudentPopupComponent } from './add-student-popup/add-student-popup.component';
#Component({
selector: 'app-create-course',
templateUrl: './create-course.component.html',
styleUrls: ['./create-course.component.scss']
})
export class CreateCourseComponent implements OnInit, AfterViewInit {
bsModalRef!: BsModalRef;
emails: string[] = [];
isEmpty: boolean = true;
#ViewChild(AddStudentPopupComponent) addStudent!: AddStudentPopupComponent;
constructor(private modalService: BsModalService) { }
ngOnInit(): any {}
ngAfterViewInit(): void {
if (this.addStudent) {
this.emails = this.addStudent.emails;
isEmpty = false;
}
}
openAddStudentModal() {
this.bsModalRef = this.modalService.show(AddStudentPopupComponent, {class: 'modal-lg'});
this.bsModalRef.content.closeBtnName = 'Close';
}
}
I want to use the updated "emails" array in my front end view. The view part using this array should be updated.
View part
When the popup is filled and submitted the emails array is populated and it should update the this view part.
<div class="multipleInput-container" *ngIf="!isEmpty;else noEmails">
<div class="col-lg-12">
<ul *ngFor="let email of emails">
<li class="multipleInput-email">{{ email }}</li>
</ul>
</div>
</div>
<ng-template #noEmails>
<div class="col-lg-3">
<input type="text" class="form-control form-control-sm"
placeholder="No Students Added" aria-label="No Students Added">
</div>
</ng-template>
Thanks in Advance
You should use #Output
In AddStudentPopupComponent
emails: string[] = [];
#Output() sendEmail = new EventEmitter();
sendData() {
this.sendEmail.emit(this.emails);
}
then in create-course.component.html file
<app-add-student-popup (sendEmail)="emails = $event"></app-add-student-popup>

Form.io form builder how to emit or submit data

I am building a dynamic drag and drop form builder and i cant find a way to console log out the data of the form. here is the form component.html in which i am rendering the drag and drop form
<div>
<form-builder [form]="form" (change)="onChange($event)" (submit)="onSubmit($event)"></form-builder>
<div class="well jsonviewer">
<pre id="json"><code class="language-json" #json></code></pre>
</div>
</div>
And here is the component.ts I just wanted to console the form data out then I will send it to the
API to be saved.
import { Component, OnInit, ElementRef, ViewChild } from '#angular/core';
#Component({
selector: 'app-user-add',
templateUrl: './user-add.component.html',
styleUrls: ['./user-add.component.css']
})
export class UserAddComponent implements OnInit {
title = 'ASW Form Builder Demo';
jsonData:any[]=[];
#ViewChild('json') jsonElement?: ElementRef;
constructor() { }
ngOnInit(): void {
}
// Publish Template
saveJsonData(data: any){
//....
console.log(data);
// do something
}
//Preview Template
previewTemplate(data: any){
this.jsonData = data;
}
public form: Object = {components: []};
onChange(event) {
console.log(event.form);
}
onSubmit(param){
console.log(param);
}
}
Can anyone help me fetch the data from the form on submit? and can i do this on another division and button outside the form? I wanted to use my own submit button. or is there any tutorial that can explain this starting from the database design?
you will need to attach entire form object to your ts variable. Below is the code snippet that works for me.
HTML
<div>
<form-builder [form]="form" (change)="onChange($event)" (submit)="onSubmit($event)" #formio></form-builder>
<div class="well jsonviewer">
<pre id="json"><code class="language-json" #json></code></pre>
</div>
</div>
ts
import { Component, OnInit, ElementRef, ViewChild } from '#angular/core';
#Component({
selector: 'app-user-add',
templateUrl: './user-add.component.html',
styleUrls: ['./user-add.component.css']
})
export class UserAddComponent implements OnInit {
#ViewChild('formio') formIO: any;
title = 'ASW Form Builder Demo';
jsonData:any[]=[];
#ViewChild('json') jsonElement?: ElementRef;
constructor() { }
ngOnInit(): void {
}
// Publish Template
saveJsonData(data: any){
//....
console.log(data);
// do something
}
//Preview Template
previewTemplate(data: any){
this.jsonData = data;
}
public form: Object = {components: []};
onChange(event) {
console.log(event.form);
}
onSubmit(param){
// You can use this.formIO.form to get the entire json
console.log(this.formIO.form);
}
}
As I saw you are using asw form builder which is easy to use and creates rapid development and design web forms that includes several controls.
Firstly, you need to create a form with the help of asw form builder with submit button after that once you will click on the submit button form builder will be emitting the JSON data in submit method.
like for example:
HTML Code:
<asw-form-builder [uploadData]="jsonData1"
[isShowPreviewButton]="isShowPreviewButton"
[isShowJsonDataButton]="isShowJsonDataButton"
[isShowPublishButton]="isShowPublishButton"
(publishClick)="saveJsonData($event)"
(previewClick)="previewTemplate($event)"
(buttonClick)="buttonClick($event)"
(aswModelChange)="onSelectionChange($event)"></asw-form-builder>
Component code:
export class AppComponent {
title = 'ASW Form Builder Demo';
jsonData: any[] = [];
jsonData1: any[] = [];
isShowPreviewButton = false;
isShowJsonDataButton = true;
isShowPublishButton = false;
// Publish Template
saveJsonData(data: any){
//....
console.log(data);
// do something
}
//Preview Template
previewTemplate(data: any){
this.jsonData = data;
}
// when you click on submit button form builder will call this method
buttonClick(data: any): void {
console.log(data);
}
// form builder will call this method when any control model will be changed
onSelectionChange(control: any): void {
console.log(control);
}
}
HTML code for preview created form:
<asw-preview-template [formContainer]="jsonData"
(buttonClick)="buttonClick($event)"
(aswModelChange)="onSelectionChange($event)">
button click and onSelectionChange method should be the same as it is
below is the GitHub URL for the demo and documentation
https://github.com/asoftwareworld/ASW-Form-Builder
Please let us know if you need any help on this

Angular: How to get value from one component's frontend (app.compont.html) to another component's backend (other.component.ts)

Consider a simple crud scenario. I have a lot of input fields and buttons in app.component.html. When i press a button from app.component.html, it will send html field value to 'other.component.ts' component and will display the result back in app.component.html after processing (like add, subtract or other).
Here is app.component.html
<a routerLink="posts/">Show Posts</a>
<input type="number" [(ngModel)]="get-one-post-id">
<a routerLink="/post-by-id">Show One Posts</a>
<router-outlet>
</router-outlet>
post-by-id-component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
import { Observable } from 'rxjs';
#Component({
selector: 'app-post-by-id',
templateUrl: './post-by-id.component.html',
styleUrls: ['./post-by-id.component.css']
})
export class PostByIdComponent implements OnInit {
posts: object;
constructor(private dataService: DataService) { }
ngOnInit(): void {
// const id = ??
this.GetPost(1);
}
async GetPost(id: number)
{
const response = await this.dataService.Get_A_Post(id);
const dataService = await response.json();
this.posts = dataService;
}
}
post-by-id-component.html
<div *ngFor="let post of posts">
<h3>{{post.title}}</h3>
<p>{{post.body}}</p>
</div>
I just want to get value from the field called get-one-post-id from app.component.html to post-by-id-component.ts [where I commented // const id = ??]. But i can't find a way to import it.
To share Data between Angular Components exists 4 different ways:
Parent to Child: Sharing Data via Input
Child to Parent: Sharing Data via ViewChild
Child to Parent: Sharing Data via Output() and EventEmitter
Unrelated Components: Sharing Data with a Service
You can read this useful article to see how it works.

How to call a function from another component [Angular]

I'm new to Angular. This question is very much similar to mine but doesn't answers my question. In my case, the two components are stand-alone, that means they ain't parent-child to each other. They're separate and at same directory level. That's why my problem is different from the rest. I tried using:
#ViewChild();
#Output() ....EventEmitter()
But I'm still getting an error in navbar.component.ts:
ERROR TypeError: "this.articles is undefined"
My first component is NavBar and my second component is Articles
So the scenarioa is, pressed() method of NavBar have to call callSearch(arg) method of Articles.
Here is my navbar.component.ts
import { ..., ViewChild } from '#angular/core';
import { ArticlesComponent } from '../articles/articles.component';
#Component({
...
})
export class NavbarComponent implements OnInit {
text='something';
#ViewChild(ArticlesComponent, {static: false}) articles: ArticlesComponent;
constructor() { }
/* This method is called on click event from HTML page*/
pressed(text: string) {
this.articles.callSearch(text);
}
ngOnInit() {
}
}
navbar.component.html
<li class="nav-item">
<button class="btn" (click)="pressed(text)">Search</button>
</li>
And here is the component whose method I want to call from NavBar.
articles.component.ts
import { ... } from '#angular/core';
#Component({
...
})
export class ArticlesComponent implements OnInit {
articles = [];
filteredArticles=[];
constructor(...) { }
ngOnInit() {
...
}
/* this is called from navbar typescript and it will call SearchFunction below*/
callSearch(text: string) {
this.SearchFunction(text);
}
SearchFunction(text: string) {
this.filteredArticles=(this.articles.filter(e => {
/* some logic*/
}));
}
}
articles.component.html
<div *ngFor="let article of filteredArticles; let i = index;">
<div class="card text-center">
<div class="card-body">
<!-- card design related html -->
</div>
</div>
</div>
Please correct me.
PS: Here is the stackblitz.
To communicate two components that are not related to each other, you can use a service.
#Injectable({
providedIn: 'root',
})
export class YourService {
private yourVariable: Subject<any> = new Subject<any>();
public listenYourVariable() {
return this.yourVariable.asObservable();
}
private yourVariableObserver(value : type) {
this.yourVariable.next(value);
}
You import in yours components where you want use it this service.
import{ YourService } from ...
In component you want write the data call:
this.yourService.yourVariableObserver(yourData);
while where you want read the data:
this.yourService.listenYourVariable().subscribe(
variable => {
this.data = variable;
this.callyourFunction();
}
)
Obviously you can simple call the function without pass any value.

Cannot display JSON API result from console to html page

Cannot display the console result in the html page
and this is the code of the TS component (home.component.ts)
import { Component, OnInit } from '#angular/core';
import { Http, Response } from '#angular/http';
import {Router } from '#angular/router';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(
private http: Http,
public router:Router
) {}
ngOnInit() {}
source="";
destination="";
date="";
names="";
searchCity(){
this.http.get("http://127.0.0.1:8000/restapi/?source="+this.source+"&destination="+this.destination+"&date="+this.date+"")
.subscribe(
(res:Response) => {
this.router.navigate(['test']);
const searchFlight= res.json();
console.log(searchFlight);
//this.names = searchFlight.names;
}
)
}
}
This is the page where i want to display the result (test page) (this.router.navigate(['test']);)
(test.component.html)
<div class="hl1"></div>
{{names}}
{{prices}}
<div class="hl1"></div>
and thess are the params i get
(home.component.html)
<input type="text" placeholder="From ..." [(ngModel)]=source name="source">
<input type="text" placeholder="To ..." [(ngModel)]=destination name="destination">
<input type="text" class="input datepicker" value="Mm/Dd/Yy" [(ngModel)]=date name="date">
<button (click)=searchCity() type="submit">Search</button>
and this is the console result
enter image description here
Conosole.log is to show debug prints in Console no in HTML.
To see the service results in HTML you must to get them from response object
example:
... first init you variables to see them on html
this.names = "Sample"
this.prices = 5;
... then apply this code inside your function
this.http.get("http://127.0.0.1:8000/restapi/?source="+this.source+"&destination="+this.destination+"&date="+this.date+"")
.subscribe(
(res:Response) => {
this.router.navigate(['test']);
searchFlight= res.json();
console.log(searchFlight);
this.names = searchFlight.names;
this.prices = searchFlight.prices;
}
)
... Advice: check you api result, and check if you problem is just update the DOM
The way you are trying to see the data will only show you on the Console. You can use Firebug or Chrome Developer Tools (Ctrl+Shift+I) and you can see the object. If you need to print it on the screen you can do something like this:
...
export class HomeComponent implements OnInit {
constructor( private http: Http, public router:Router ) {}
ngOnInit(){}
get printObject() {return JSON.stringify(this.object)}; //set this method
and you can use this in your template like
<div> {{printObject}} </div>
What this does is sets a method on the controller that returns a stringified representation of the object. If you have an array, try something like this in your template
<ul>
<li *ngFor="let object of array">{{object | json}}</li>
</ul>

Categories

Resources