Angular: Filter Service via API request - javascript

I am using a filter and need to read the value in order to send an API request with the values in the url.
I use this API. I am able to filter both of the categories. After selecting two, we wanna send an API request with both selected values in the url.
We generated a backend-side script to filter, all I need to do is sending a request with the modified url.
app.component.ts
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
lines: any[];
filteredLines: any[];
filterBy;
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get("https://api.mocki.io/v1/26fce6b9").subscribe(lines => {
this.lines = lines;
this.filteredLines = [...this.lines];
});
}
filter() {
this.filteredLines = [
...this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
];
}
/** Here I need a script onClick button that reads the selected values and sending a get-request of API link above added with the filtered values:
With click on the submit-button, I want to send the API request.
If api.com/data is the link, the request link would be like api.com/data?line=A&workCenter=1
The "?" is for category Line, and "&" for workCenter.
**/
}
}
app.component.html
<select>
<option>Line</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.line}}
</option>
</select>
<select>
<option>Work Center</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.workCenter}}
</option>
</select>
<form action="" method="post">
<input type="submit" name="request" value="Submit" />
</form>
I have created a Stackblitz project for better understanding.

From your example, you need to add [(ngModel)] which will bind to the selected value.
You can find more info on how to properly use a select here More info
<select [(ngModel)]="selectedLine">
<option>Line</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.line}}
</option>
</select>
<select [(ngModel)]="selectedWorkCenter">
<option>Work Center</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.workCenter}}
</option>
</select>
<form action="" method="post">
<input type="submit" name="request" value="Submit" (click)="Submit()" />
</form>
Then in your ts file, declare the select variable and access value as in the click function Submit.
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
lines: any[];
filteredLines: any[];
filterBy;
selectedLine; // For first select
selectedWorkCenter; // For second select
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get("https://api.mocki.io/v1/26fce6b9").subscribe(lines => {
this.lines = lines;
this.filteredLines = [...this.lines];
});
}
filter() {
this.filteredLines = [
...this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
];
}
requestAnDieAPI() {
console.log(this.filteredLines); // hier muss mein API post request hin
}
Submit() {
var baseUrl = `https://api.mocki.io/`;
var url = `${baseUrl}data?line=${this.selectedLine}&workCenter=${
this.selectedWorkCenter
}`;
this.http.get(url).subscribe(response => {
// response
});
}
}

It is not clear for me if you want to send multiple { line, workCenter } objects to the API call, but from how you setted up the Stackblitz project I will assume you want to send just a single one.
Never seen a (keyup) on an <option> element, use [(ngModel)] on the <select> instead:
<select [(ngModel)]="selected.line">
<option [value]="null">Line</option>
<option *ngFor="let dropdown of filteredLines" [value]="dropdown.line">
{{dropdown.line}}
</option>
</select>
<select [(ngModel)]="selected.workCenter">
<option [value]="null">Work Center</option>
<option *ngFor="let dropdown of filteredLines" [value]="dropdown.workCenter">
{{dropdown.workCenter}}
</option>
</select>
<!-- the use of the form in this case is not required -->
<!-- since you are using requestAnDieAPI to do the api call -->
<form action="" method="post" (submit)="requestAnDieAPI()">
<input type="submit" name="request" value="Submit" />
</form>
<!-- You can also use just a simple button -->
<button (click)="requestAnDieAPI()">Submit</button>
Then your component (model) should contain a selected variable that map the interface (view)
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
lines: any[];
filteredLines: any[];
filterBy;
selected = {
line: null,
workCenter: null
};
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get("https://api.mocki.io/v1/26fce6b9").subscribe((lines: any[]) => {
this.lines = lines;
// this.filteredLines = [...this.lines];
// better:
this.filteredLines = this.lines.slice();
// or either this.filter() directly
});
}
filter() {
// this.filteredLines = [
// ...this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
// ];
// this is redundant, better:
this.filteredLines = this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
}
requestAnDieAPI() {
if (this.selected.line != null && this.selected.workCenter != null) {
let apiUrl = "https://api.com/data?line=" + this.selected.line +
"&workCenter=" + this.selected.workCenter
this.http.get(apiUrl).subscribe(/* Your optional response callback/subscriber here */);
}
}
}

Related

How to pop up a modal from click in dropdown list option

Good day developers , im working in this app with angular , and now im trying to once one of the options
get clicked , to show a modal tag .
Basically what i did was create a paralell template equal to the item selected on the dropdown , and over this template using the a tag i set all the logic to show the modal, but guess isn't user friendly cause of couple extra clicks.Trying to set the a tag inside the options also wasn't viable cause the my dropdown didn't work.Here a mock about what i did:
HTML tag
<select [hidden]="!state" name="optionsInc" required [(ngModel)]="optionsInc" (change)="subItemSelected($event)">
<option value="select" [ngValue]="null" [disabled]="true">Select Income</option>
<option *ngFor="let item of allKeysIncomings" label="{{item}}" value="{{item}}"></option>
</select>====>DROPDOWN LIST LOGIC
<p [hidden]="!state"> <a *ngIf="incomeSelected"
href="#"
class="btn btn-primary btn-block"
data-toggle="modal"
data-target="#editItem"
>{{incomeSelected}}</a>
</p>====>PARALELL REFERENCE TO POP THE MODAL UP
<div class="modal fade" id='editItem'>======>MODAL
SOME TAGS AND CODE
</div>
then on my component i did this :
imports...
#Component({
selector: 'app-user-sheet-balance',
templateUrl: './user-sheet-balance.component.html',
styleUrls: ['./user-sheet-balance.component.css'],
})
export class UserSheetBalanceComponent implements OnInit {
allKeysIncomings: any;==>ITERABLE
incomeSelected: string;
constructor(some code) {}
ngOnInit(): void {some code}
async subItemSelected(event) {
SOME CODE
return (
await (this.incomeSelected = event.target.value),
);
}
All this process does the task on activate the modal once i click the tag a, but instead of creating that paralell reference to the dropdown, im wondering if is possible to do it straight from the dropdown in fact.
I have been watching some similar issues on the comunity like
:Open a Modal Using an Option from a Dropdown - Angular 2 + ngx
but doesn't work on my code specifications.
Any updated idea about this ?.Thanks in advance!!!!!!
if you have Component with dialog layout in ModalComponent it should work as follow
import { Injectable } from '#angular/core';
import { MatDialog, MatDialogRef } from '#angular/material/dialog';
import { ModalComponent } from './modal/modal.component';
#Injectable({
providedIn: 'root'
})
export class TestDialogService {
dialogRef: MatDialogRef<ModalComponent, any>;
constructor(public dialog: MatDialog) { }
open() {
if(this.dialogRef) {
this.dialogRef.close();
}
this.dialogRef = this.dialog.open(ModalComponent, {
panelClass: 'app-dialog'
});
}
close() {
if(this.dialogRef) {
this.dialogRef.close();
}
}
}
// html
<mat-form-field>
<mat-label>Favorite car</mat-label>
<select name="optionsInc"
matNativeControl
[(ngModel)]="optionsInc"
(ngModelChange)="onModelChange()">
<option value="select" [value]="null" [disabled]="true">Select Income</option>
<option *ngFor="let item of allKeysIncomings" [label]="item.viewValue"
[value]="item.value"></option>
</select>
</mat-form-field>
// ts
#Component({
selector: 'app-root',
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"]
})
export class AppComponent {
state = false;
optionsInc = null;
allKeysIncomings = [
{value: 'volvo', viewValue: 'Volvo'},
{value: 'saab', viewValue: 'Saab'},
{value: 'mercedes', viewValue: 'Mercedes'}
];
constructor(
public testDialogService: TestDialogService) {
}
onModelChange() {
this.testDialogService.open();
}
}
example

Angular 6 Form not passing variable to URL

I am trying to create a form in angular that takes a name, passes it to a URL, and returns a portion of a .json file. I can't figure out why the url is not getting updated though.
The HTML:
<form (ngSubmit)="processForm($engineer)">
<div class="form-group">
<label for="engineerselectform">Engineer Name</label>
<select class="form-control" id="engineerselectform" name="engineer" [(ngModel)]="engineer">
<option></option>
<option>Smith</option>
<option>Jones</option>
<option>Clark</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="submit" aria-pressed="true">
</form>
The Component:
import { Component, OnInit } from '#angular/core';
import { ScheduleService } from '../schedule.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-schedule',
templateUrl: './schedule.component.html',
styleUrls: ['./schedule.component.scss']
})
export class ScheduleComponent implements OnInit {
engineer;
constructor(
private scheduleService: ScheduleService,
private route: ActivatedRoute
) { }
ngOnInit() {}
processForm(engineer: string) {
this.route.params.subscribe(params=> { const engineer = params["engineer"];
this.scheduleService.getschedule(engineer).subscribe(engineer => this.engineer = engineer);
});
}
}
The Service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ScheduleService {
apiUrl ='http://127.0.0.1:5000/schedule'
engineer;
constructor(private http: HttpClient) { }
getschedule(engineer: string){
return this.http.get(`${this.apiUrl}?engineer=${this.engineer}`);
}
}
The Flask API backend:
#app.route('/schedule', methods = ['GET'])
def engineer_location_api():
if "engineer" in request.args:
print ('did this')
engineer_name = request.args["engineer"]
print ("engineer name:", engineer_name)
else:
return "not found, sorry"
answer = {}
with open(LOC1, "r") as file:
check_loc1 = json.load(file)
for item in check_loc1["LOC1"]:
if engineer_name in item["Engineer"]:
answer.update(item)
else:
continue
with open(LOC2, "r") as file:
check_loc2 = json.load(file)
for item in check_loc2:
if engineer_name in item:
answer.update(item)
else:
continue
if answer:
return answer
else:
return 'engineer not found'
app.run()
the error:
ERROR
Object { headers: {…}, status: 200, statusText: "OK", url: "http://127.0.0.1:5000/schedule?engineer=undefined", ok: false, name: "HttpErrorResponse", message: "Http failure during parsing for http://127.0.0.1:5000/schedule?engineer=undefined", error: {…} }
core.js:6014:19
As I understand it, when I hit submit the process form function should send the engineer variable to the component where it sets it as a parameter that it provides to the service which should fill out the URL. But regardless of how I play around with it, the engineer always comes back as undefined. Clearly I'm missing something core to passing the variable.
Also, I'm super new and therefore there are probably other things in this code that are ugly or not best practice, feel free to rip into it, I figure my understanding can only go up.
You don't have to subscribe to activated url if your data is coming from form. You have to remove the $event from processForm because we will add the global variable in your service function. Please have a look on below example
<form (ngSubmit)="processForm()">
<div class="form-group">
<label for="engineerselectform">Engineer Name</label>
<select class="form-control" id="engineerselectform" name="engineer" [(ngModel)]="engineer">
<option></option>
<option value="smith">Smith</option>
<option value="jones">Jones</option>
<option value="clark">Clark</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="submit" aria-pressed="true">
</form>
import { Component, OnInit } from '#angular/core';
import { ScheduleService } from '../schedule.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-schedule',
templateUrl: './schedule.component.html',
styleUrls: ['./schedule.component.scss']
})
export class ScheduleComponent implements OnInit {
engineer;
receivedEngineers;
constructor(
private scheduleService: ScheduleService,
private route: ActivatedRoute
) { }
ngOnInit() {}
processForm() {
this.scheduleService.getschedule(this.engineer).subscribe(engineer => this.receivedEngineers = engineer);
});
}
}
getschedule(engineer: string){
return this.http.get(`${this.apiUrl}?engineer=${engineer}`);
}
The engineer is now accessed from parameter of getSchedule() function.

Can't fill and post value from dropdown in Angular

When I load page, my Category dropdown is automaticly filled with data from database, then I want select value from that dropdown and on button click post data to given url. On page load, dropdown is filled correctly without any error, but when I select any value in dropdown I get this error:
ERROR Error: Error trying to diff 'c'. Only arrays and iterables are allowed
How can I resolve this error?
My add-form.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { FormGroup, NgForm } from '#angular/forms';
interface LoginFormModel{
productName?: string;
retailPrice?: string;
wholesalePrice?: string;
category?: Category;
type?: string;
productionStart?: string;
productionEnd?: string;
}
interface Category{
id?: number;
name?: string;
}
#Component({
selector: 'app-add-form',
templateUrl: './add-form.component.html',
styleUrls: ['./add-form.component.scss']
})
export class AddFormComponent implements OnInit {
model: LoginFormModel= {};
category: Category = {};
form?: FormGroup;
constructor(private httpClient: HttpClient) { }
ngOnInit() {
this.httpClient.get('http://localhost:8090/api/category/')
.subscribe(data => {
this.model.category = data;
console.log(this.model.category);
}, err => {
console.log('Error: ', err);
})
}
eventSubmit(form: NgForm){
if(form.invalid){
return;
}else{
this.onSubmit();
}
}
onSubmit() {
console.log(this.model);
this.httpClient.post('http://localhost:8090/api/product/',this.model)
.subscribe(data => {
console.log(data);
})
}
}
Dropdown:
<div class="form-group">
<label class="col-md-3 control-label" for="category">Category:</label>
<div class="col-md-9">
<select class="form-control" required id="sel2" name="category" class="form-control" #formInput="ngModel"
[(ngModel)]="model.category">
<option *ngFor="let c of model.category" value="c">{{c.name}}</option>
</select>
<div class="invalid-feedback">
Category is required!
</div>
</div>
</div>
I think there is a mistake on this line,
<option *ngFor="let c of model.category" value="c">{{c.name}}</option>
I think that value="c" should be something like [value]="c.value" or value="{{c.value}}"
If not change it to this,
[value]="c.name"

angular 6: trying loop throw an object (via *ngFor) after choosing a value of a 'select'

I'm trying to build a "quick order" component for ordering movies.
The first element is a 'select'. i get the results via http request and then render the options.
When the user is choosing an option of a movie, i need to display him another select which shows available dates. i need to render the select according to an object who got string dates as his keys.
e.g:
{
"2018-07-19": {
"00:10": "5b4f445da2c93e36c4f1a1ca",
"01:00": "5b4f355ab6334b27fc031adb",
"13:44": "5b4f43fda2c93e36c4f1a1c9"
},
"2018-07-25": {
"23:00": "5b4f357db6334b27fc031adc"
}
}
everything is working fine with the rendering of the movieList select and with retrieving the dates object. but when i add the html code of the second select (id=selectDate), i get an error.
Here is my code:
ts:
import { Component, OnInit } from '#angular/core';
import { MoviesService } from '../services/movies.service';
import { ShowService } from '../services/show.service';
import { Observable } from 'rxjs';
import * as moment from 'moment';
#Component({
selector: 'app-quick-order',
templateUrl: './quick-order.component.html',
styleUrls: ['./quick-order.component.css']
})
export class QuickOrderComponent implements OnInit {
movieList: any;
movieShowsSchedule: any;
selectedMovie: any;
selectedDate: any;
constructor(private moviesService: MoviesService, private showService: ShowService) { }
ngOnInit() {
this.movieList = this.moviesService.getMovies();
}
onChangeSelectMovie() {
this.movieShowsSchedule = this.showService.getMovieSchedule(this.selectedMovie).subscribe(res => {
alert("we got movie successfully");
console.log(res);
}, err => {
alert("we did not get movie");
});
}
onChangeSelectDate() {
}
}
html:
<div class="form-group">
<label for="selectMovie">Movie:</label>
<select id="selectMovie" [(ngModel)]="selectedMovie" (change)="onChangeSelectMovie()">
<option *ngFor="let movie of movieList | async" value="{{movie._id}}" >{{movie.title}} </option>
</select>
<label for="selectDate">Date:</label>
<select id="selectDate" [(ngModel)]="selectedDate" (change)="onChangeSelectDate()">
<option *ngFor="let date in movieShowsSchedule | async" value="{{date}}" >{{date}}</option>
</select>
</div>
Anybody knows what is the problem? and how can make this code work?
Many thanks!
There are several issues.
Since you're using async, you should set moveShowSchedule to the result of the Observable not the Subscription, or easier still, don't use async.
You can use map to convert movieShowSchedule into a usable model for your view.
You should replace in with of in the *ngFor.
COMPONENT
movieShowsSchedule = [];
onChangeSelectMovie() {
this.showService.getMovieSchedule(this.selectedMovie).subscribe(x => {
this.moveShowSchedule = [];
for (let key in x) {
this.moveShowSchedule.push({ key, date: x[key].date });
}
});
}
HTML
<option *ngFor="let x of movieShowsSchedule" [ngValue]="x.date">
{{x.date}}
</option>
I didn't want to refactor your whole code, but if you created an Observable bound to the change event you could then use switchMap to update a movieShowSchedule Subject.

Selects' events in Angular2

Please, can you help me? It is supposed to be easy, but I can't find the solution. There is a form with two selects. When #select1 changes, #select2 needs to show data according to the value of #select1. For example, get cities of each state. Kind of :
//html
<select (change)="select2.getCities($event)" ng-control="userState">
<option *ng-for="#state of states" [value]="state">{{state}}</option>
</select>
<select #select2 ng-control="userCity">
<option *ng-for="#city of cities" [value]="city">{{city}}</option>
</select>
//the Component
#Component({ selector: 'user-management', appInjector: [FormBuilder] });
#View({ templateUrl: 'user-management.html', directives: [NgFor] });
export class userManagement {
constructor(fb: FormBuilder){
this.userForm = fb.group({
userState: [],
userCity: []
});
this.states = ['New York', 'Pennsylvania'];
this.cities = {'New York': ['Albany', 'Buffalo'], 'Pennsylvania':['Pittsburgh', 'Philadelphia']};
}
getCities($event){
return this.cities[$event.target.value];
}
}
This, of course, doesn't work. PLEASE, do you know how it should be done? It's in alpha28.
Great! I found out how to make it work! :) The only thing that was missing, was the form model passed to the event. It should be like this:
<form [ng-form-model]="userForm">
<select (change)="select2.getCities($event, userForm)" ng-control="userState">
<option *ng-for="#state of states" [value]="state">{{state}}</option>
</select>
Answering with Angular 2 latest template syntax and Typescript component
//The Component Type script
import {Component} from 'angular2/core';
import {NgForm} from 'angular2/common';
#Component({ selector: 'states-cities',
template: `
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
<select ngControl="state" #state="ngForm" (change)="getCities(state)">
<option *ngFor="#state of states" [value]="state" >{{state}}</option>
</select>
<select ngControl="userCity" #select2="ngForm">
<option *ngFor="#city of cities" [value]="city">{{city}}</option>
</select>
</form>
`
})
export class stateCitiesComponent {
states= ['New York', 'Pennsylvania'];
cities = [];
citiesData={'New York': ['Albany', 'Buffalo'], 'Pennsylvania':['Pittsburgh', 'Philadelphia']};
getCities(state){
this.cities=this.citiesData[state.value];
}
}
This is how I would do it on Angular 2 RC5, with a model-driven approach and Observables. This could also be a search field where you then use debounceTime() to not hit your backend on every keystroke or manipulate the input further.
//The Component Type script
import { Component } from '#angular/core';
import { FormControl, FormGroup, FormBuilder } from '#angular/forms';
#Component({
moduleId: module.id,
selector: 'states-cities',
template: `
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<select formControlName="state">
<option *ngFor="let state of states" [value]="state" >{{state}}</option>
</select>
<select formControlName="userCity">
<option *ngFor="let city of cities" [value]="city">{{city}}</option>
</select>
</form>
`
})
export class stateCitiesComponent {
states:Array<string>;
cities:Array<string>;
citiesData:any;
myForm:FormGroup;
constructor(private formBuilder: FormBuilder) {
this.states = ['New York', 'Pennsylvania'];
this.cities = [];
this.citiesData = {'New York': ['Albany', 'Buffalo'], 'Pennsylvania':['Pittsburgh', 'Philadelphia']};
// Setup Form
this.myForm = this.formBuilder.group({
state: [''],
userCity: ['']
});
// Now setup change detection with an Observable
this.myForm.controls["state"].valueChanges
.debounceTime(100) // wait a litle after the user input (ms)
.subscribe(state => {
this.cities = this.citiesData[state];
});
}
onSubmit() {
// do something
}
}
You can read more about change detection here.

Categories