Angular - View prints old values along with new values - html

Using Angular. I have a variable modelResponse which gets updated and the new value prints. But along with it, in the html, all of its old values are also printed.
I have used the 2 way data binding on modelResponse in the html [(ngmodel)]= {{{{modelResponse}}}}
home-page.component.html
<span><a mat-raised-button style="margin-left:5rem" color="accent" (click)=show()><b>Score the
Model</b></a></span>
<br>
<br>
<div class=" example-container" *ngIf=showdirectPredict>
<form
style="background-color: cornsilk; size: 0.8rem; font-style: italic;font-family: Arial, Helvetica, sans-serif;font-size: 0.8rem;border-top-right-radius: 0.5rem;border-bottom-left-radius: 0.5rem;border-bottom-right-radius: 0.5rem;border-top-left-radius: 0.5rem"
(ngSubmit)="makepredictrequest()" #myForm="ngForm">
<p>
<br>
<b style="margin-left: 1rem;">Enter the Embedding Dimensions</b>
<br>
<br>
<mat-form-field class="fields" appearance="fill" style="margin-left:1rem">
<mat-label>Enter ED d0</mat-label>
<input matInput placeholder="d0" [(ngModel)]="dee0" name="d0-dimension">
<!-- <mat-hint>We need your name for the ID badge ;) !</mat-hint>-->
</mat-form-field>
<button mat-raised-button type="submit" style="margin-left:2rem" color="primary" md-raised-button>Submit</button>
<button mat-raised-button type="submit" style="margin-left:1rem" color="primary" (click)=dontshow()
md-raised-button>Close</button>
<b style="margin-left: 10rem;"> RESULT : This Non-CRU customer belongs to Cluster Number : {{modelResponse}} </b>
</p>
<br>
<br>
</form>
home-page.component.ts
import { Component, OnInit } from '#angular/core';
import { User } from '../User.model';
import { Embeddings } from '../embeddings.model';
import { CommonModule } from '#angular/common';
import { BrowserModule } from '#angular/platform-browser';
import { AccountService } from '../account.service';
import { D0embed } from '../d0embed';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
showdirectPredict = false;
modelResponse: any;
lastResponse: any;
modelname: any;
dee0: any;
ed0: D0embed;
d0: D0embed[] = [];
embedding: Embeddings = new Embeddings();// initiate all arrays in this model via constructor or here
modelResponseString: any;
constructor(private serv: AccountService) {
}
ngOnInit() {
}
makepredictrequest() {
console.log('In makepredictrequest()');
this.ed0 = this.dee0;
this.embedding.d0.push(this.ed0)
this.serv.scoreModel(this.embedding).subscribe((data: any) => {
this.modelResponse = data['value'];
console.log('Request finished');
this.lastResponse = this.modelResponse[this.modelResponse.length - 1];
console.log('The data received is :' + this.lastResponse);
});
}
show() {
this.showdirectPredict = true;
}
dontshow() {
this.showdirectPredict = false;
}
}
Using
RESULT : This Non-CRU customer belongs to Cluster Number : {{modelResponse}}
gives me for example,
On clicking scoreModel() first time ,
RESULT : This Non-CRU customer belongs to Cluster Number : 5
On clicking scoreModel() second time ,
RESULT : This Non-CRU customer belongs to Cluster Number : 5, 13
On clicking scoreModel() third time ,
RESULT : This Non-CRU customer belongs to Cluster Number : 5, 13, 2
All I want to see everytime is ofcourse the current value of the Cluster number, i.e the modelResponse.

It seems that modelResponse field is an array of numbers and the lastResponse is the last number in that array, i.e. the value that you need. But template binding looks like This Non-CRU customer belongs to Cluster Number : {{modelResponse}}.
Try changing it to This Non-CRU customer belongs to Cluster Number : {{lastResponse}}.

Related

Not mandatory option selection in Autocomplete Angular Material [duplicate]

I'm trying to implement the autocomplete component from Angular Material:
https://material.angular.io/components/autocomplete/overview
It works well for letting the user select a particular item from the suggested list but I also want to allow the user to add items not in the list.
So lets say the suggested list has the following items:
Cats
Birds
Dogs
And the user starts typing "Do" and the autocomplete shows "Dogs" as the suggested option (because I'm also filtering the list based on what they type). But then the user continues typing "Dolls" and now nothing is displayed in the autocomplete suggestions. Then the user hits enter and it gets added to the list.
Current behavior is that if what the user typed doesn't exist in the list then they are unable to add the item.
If you add an enter key listener to the input field, you can process the entered value and add it to the options if it doesn't exist. You can also dynamically add whatever the user enters to the list of filtered options as an "add new item" option, or add an "add" icon to the field (e.g. as a matSuffix). Or you can do all three:
Stackblitz
HTML
<form class="example-form">
<mat-form-field class="example-full-width">
<input matInput placeholder="Item" aria-label="Item" [matAutocomplete]="auto" [formControl]="itemCtrl" (keyup.enter)="addOption()">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="optionSelected($event.option)">
<mat-option *ngFor="let item of filteredItems | async" [value]="item">
<span>{{ item }}</span>
</mat-option>
</mat-autocomplete>
<button *ngIf="showAddButton && itemCtrl.value" matSuffix mat-button mat-icon-button (click)="addOption()"><mat-icon matTooltip='Add "{{itemCtrl.value}}"'>add</mat-icon></button>
</mat-form-field>
</form>
TS
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
import { startWith } from 'rxjs/operators/startWith';
import { map } from 'rxjs/operators/map';
/**
* #title Autocomplete with add new item option
*/
#Component({
selector: 'autocomplete-overview-example',
templateUrl: 'autocomplete-overview-example.html',
styleUrls: ['autocomplete-overview-example.css']
})
export class AutocompleteOverviewExample {
itemCtrl: FormControl;
filteredItems: Observable<any[]>;
showAddButton: boolean = false;
prompt = 'Press <enter> to add "';
items: string[] = [
'Cats',
'Birds',
'Dogs'
];
constructor() {
this.itemCtrl = new FormControl();
this.filteredItems = this.itemCtrl.valueChanges
.pipe(
startWith(''),
map(item => item ? this.filterItems(item) : this.items.slice())
);
}
filterItems(name: string) {
let results = this.items.filter(item =>
item.toLowerCase().indexOf(name.toLowerCase()) === 0);
this.showAddButton = results.length === 0;
if (this.showAddButton) {
results = [this.prompt + name + '"'];
}
return results;
}
optionSelected(option) {
if (option.value.indexOf(this.prompt) === 0) {
this.addOption();
}
}
addOption() {
let option = this.removePromptFromOption(this.itemCtrl.value);
if (!this.items.some(entry => entry === option)) {
const index = this.items.push(option) - 1;
this.itemCtrl.setValue(this.items[index]);
}
}
removePromptFromOption(option) {
if (option.startsWith(this.prompt)) {
option = option.substring(this.prompt.length, option.length -1);
}
return option;
}
}
It's weird that the user can add an item in the suggested list. The list is suggested to the user by someone who knows what to suggest. But anyway...
The user can type anything in the field and ignore the suggestions. By ignoring the suggested Dogs and typing Dolls, user can press an "Add" button which will add whatever is typed in (Dolls) to the options array.
For example, you can do it by listening to the submit event on the form:
(ngSubmit)="options.push(myControl.value); myControl.reset()"
Here's the complete demo as well.

Can I get values from a dynamically created multiple select element?

Can I get values from a dynamically created multiple select element?
I have fixed categories of products which I intend to load dynamically from an API. Each one of those categories has an array with the options I want to be able to select. I'm stuck with it, I cant retrieve the selected values, and I recently read something that says that we can't get the selected values from a dynamically created select with angular-material. Is that true?
I've tried getting the elements by id using jQuery and have tried multiple ways of getting the selected values.
On my menu-service, which I didn't show, I print form.values but it is empty'; it should contain the selected options, or the opcEscolhidas array should contain the selected values.
Here is my template:
<div id="main" class="row">
<h2>Selecione os itens do Cardápio</h2>
<form (submit)="onCreateMenu(form)" #form="ngForm" id="items-form">
<ul class="collapsible" data-collapsible="accordion">
<li *ngFor="let categoria of categorias">
<div class="collapsible-header">{{categoria.nome}}</div>
<div class="collapsible-body">
<div class="opGroup">
<mat-form-field>
<mat-label>{{categoria.nome}}</mat-label>
<mat-select ([value])="opcEscolhidas" multiple>
<mat-option *ngFor="let opcao of categoria.opcoes" [value]="opcao">{{opcao}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</li>
</ul>
<button type="submit" class="btn">Montar Cardápio</button>
</form>
</div>
and here is my component:
import { Component, OnInit } from '#angular/core';
// import * as $ from 'jquery';
import { FormControl } from '#angular/forms';
import { MenuService } from '../menu.service';
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-create-menu',
templateUrl: './create-menu.component.html',
styleUrls: ['./create-menu.component.css']
})
export class CreateMenuComponent implements OnInit {
// feijao = "";
// arroz = "";
// macarrao = "";
// carne = "";
// acomp = "";
// salada = "";
opcEscolhidas = [];
categorias = [
{
"id":1,
"nome":"Feijão",
"opcoes": ["Carioca", "Preto", "Verde", "Macassa"]
},
{
"id":2,
"nome":"Arroz",
"opcoes": ["Branco", "Refogado", "Integral"]
},
{
"id":3,
"nome":"Macarrão",
"opcoes": ["Alho e Óleo", "Molho de tomate", "Manteiga e
cebola", "Molho branco"]
},
{
"id":4,
"nome":"Carne",
"opcoes": ["Bisteca/porco", "Carne de sol", "Peito de
frango", "Coxa de frango"]
},
{
"id":5,
"nome":"Acompanhamentos",
"opcoes": ["Purê", "Farofa", "Vinagrete", "Batata frita"]
},
{
"id":6,
"nome":"Salada",
"opcoes": ["Alface", "Tomate", "Rúcula", "Repolho"]
}
];
public menuService;
constructor(menuService: MenuService) {
this.menuService = menuService;
}
ngOnInit() {
}
onCreateMenu(form: NgForm) {
this.menuService.createMenu(form);
}
On my menu-service, which I didnt show, I print form.values, but it is empty, and it should contain the selected options. Or my "opcEscolhidas" array should contain the selected values.strong text
You need to bind ngModel to the control. Go through this video,
https://www.youtube.com/watch?v=hAaoPOx_oIw
Try this
<select
class="custom-select"
name="overallRating"
[ngModel]="inspectionGeneralInfo?.OverallRating">
<option [value]="-1">
Select a rating
</option>
<option
*ngFor="let orc of inspectionGeneralInfo?.OverallRatingChoices"
[value]="orc.AnswerCode">
{{orc.AnswerDescription}}
</option>
</select>

How to Show Placeholder if *ngFor Let Object of Objects from HTML Binding returns an empty array

I display data from a template that I create in another component (team-announcements.component)... in the main team.component.ts I use the selector for team-announcements, and add the [announcement]="announcements" and ngFor="let announcement of announcements" to load the data. If the array returns no data IE there are no announcements, how can I display a placeholder like "No Announcements"?
This is where I load the announcements in team.component.html. The data is served through an API service and is retrieved in "team.component.ts", the HTML for the objects in question is below.
team.component.ts (get announcement functions):
getAnnouncements() {
this.teamsService.getTeamAnnouncements(this.team.slug)
.subscribe(announcements => this.announcements = announcements);
console.log("announcements", this.announcements);
}
team.component.html
<div class="team-announcement">
<div class="announcement-title">Message of the Day</div>
<app-team-announcements
[announcement]="announcement"
*ngFor="let announcement of announcements">
</app-team-announcements>
</div>
This is how "app-team-announcements" above is templated in a separate file, "team-announcement.component.html" and is exported, and then used in the above code...
team-announcements.component.ts
import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '#angular/core';
import { Team, Announcement, User, UserService } from '../core';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-team-announcements',
templateUrl: './team-announcement.component.html'
})
export class TeamAnnouncementComponent implements OnInit, OnDestroy {
constructor(
private userService: UserService
) {}
private subscription: Subscription;
#Input() announcement: Announcement;
#Output() deleteAnnouncement = new EventEmitter<boolean>();
canModify: boolean;
ngOnInit() {
// Load the current user's data
this.subscription = this.userService.currentUser.subscribe(
(userData: User) => {
this.canModify = (userData.username === this.announcement.author.username);
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
team-announcements.component.html
<div class="announcement-text">
{{announcement.body}}
</div>
I am unsure of how or where to "If" check the array length to display a placeholder. Can anyone help?
If you want to hide it and display something else instead you can use the else property from *ngIf:
<div class="team-announcement">
<div class="announcement-title">Message of the Day</div>
<ng-container *ngIf="announcements.length != 0; else emptyArray">
<app-team-announcements
[announcement]="announcement"
*ngFor="let announcement of announcements">
</app-team-announcements>
</ng-container>
</div>
<ng-template #emptyArray>No announcements...</ng-template>
When you want an element with *ngFor to depend on a condition (*ngIf), a good alternative is to nest the element with an *ngFor in a <ng-container> with an *ngIf. A good thing about <ng-container> is that it wont actually be part of the DOM but will obey the *ngIf.
You could insert a div wich is only displayed when your array is empty:
<div class="team-announcement">
<div class="announcement-title">Message of the Day</div>
<app-team-announcements
[announcement]="announcement"
*ngFor="let announcement of announcements">
</app-team-announcements>
<div *ngIf="announcements.length===0"> No announcements </div>
</div>
Edit: Corrected the errors

Angular 6 - How to submit one area of a form (but not the entire form)

I am trying to submit single areas of a html page when a user clicks a 'Save' button. The html page consists of a number of tasks that can be edited, when the user clicks the save button I want the single task to be submitted to the server i.e. not all tasks to the server. What is the best way to do this. Below is my code:-
HTML:-
<mat-accordion multi="true">
<div class="task-element" *ngFor="let task of selectedDayTasks">
<div class="expansion-panel">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-form-field class="title-box">
<input matInput
value="{{ task.title }}">
</mat-form-field>
<!--{{ task.title }}-->
</mat-expansion-panel-header>
<mat-form-field class="description-box">
<textarea matInput value="[(task.description)]"></textarea>
</mat-form-field>
<!--<p>{{ task.description }}</p>-->
<mat-action-row>
<button mat-button color="warn" (click)="onSave(task._id, task.title, task.description, task.complete, task.day)">SAVE</button>
</mat-action-row>
</mat-expansion-panel>
</div>
<div class="done-button">
<button class="green-btn" *ngIf="task.complete" (click)="taskStateChange(task._id)" mat-fab>YES</button>
<button *ngIf="!task.complete" (click)="taskStateChange(task._id)" color="warn" mat-fab>NO</button>
</div>
</div>
</mat-accordion>
Task.component.ts:-
import { Component, Input } from '#angular/core';
import { Task} from './task.model';
import { DailyTaskService } from './daily-task.service';
#Component({
selector: 'app-daily-tasks',
templateUrl: './daily-tasks.component.html',
styleUrls: ['./daily-tasks.component.css']
})
export class DailyTasksComponent implements OnInit, OnChanges {
#Input() selectedDay: string;
tasks: Task[] = [];
selectedDayTasks: Task[] = [];
constructor(public dailyTaskService: DailyTaskService) {}
ngOnInit() {
this.dailyTaskService.getTasks()
.subscribe(taskData => {
this.tasks = taskData;
this.tasks.forEach((task)=> {
if (task.day == 'Monday') {
this.selectedDayTasks.push(task);
}
});
});
}
onSave(_id: number, title: string, description: string, complete: boolean, day: string ) {
this.dailyTaskService.updateTask(
_id,
title,
description,
complete,
day
);
}
}
I worked it out, I needed to use [(ngModel)] i.e. -
<input matInput [(ngModel)] = {{task.title}}">

Customer filter pipe - Angular2

In the below component view,
<h2>Topic listing</h2>
<form id="filter">
<label>Filter topics by name:</label>
<input type="text" [(ngModel)]="term">
</form>
<ul id="topic-listing">
<li *ngFor="let topic of topics | filter: term">
<div class="single-topic">
<!-- Topic name -->
<span [ngStyle]="{background: 'yellow'}">name - {{topic.name}}</span>
<!-- Topic type -->
<h3>{{topic.type}}</h3>
</div>
</li>
</ul>
Custom filter syntax is: let topic of topics | filter: term
where custom filter is:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(topics: any, term: any): any {
// check if search term is undefined
if(term === undefined) return topics;
return topics.filter(function(topic){ // javascript filter(function)
// if below is false, then topic will be removed from topics array
return topic.name.toLowerCase().includes(term.toLowerCase());
})
}
}
the component class maintains data for topics:
export class DirectoryComponent implements OnInit {
topics = [
{type:"Fiction", name:"Avatar"},
{type:"NonFiction", name:"Titanic"},
{type:"Tragedy", name:"MotherIndia"},
];
constructor() { }
ngOnInit() {
}
}
Edit: Without form tag, code works fine.
<label>Filter topics by name:</label>
<input type="text" [(ngModel)]="term">
Why custom filter FilterPipe does not filter term provided in input element?
Add brackets to your filter condition
<ul id="topic-listing">
<li *ngFor="let topic of (topics | filter: term)">
<div class="single-topic">
<!-- Topic name -->
<span [ngStyle]="{background: 'yellow'}">name - {{topic.name}}</span>
<!-- Topic type -->
<h3>{{topic.type}}</h3>
</div>
</li>
</ul>
Check the TS file
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular 5';
term : any = "avatar";
topics = [
{type:"Fiction", name:"Avatar"},
{type:"NonFiction", name:"Titanic"},
{type:"Tragedy", name:"MotherIndia"},
];
}
Remove the word function and change it to below code. refer the working version here
return topics.filter((topic)=>{
return topic.name.toLowerCase().includes(term.toLowerCase());
})
update - root cause of the issue
if you want to use NgModel inside the form tags, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions