Angular how to post data with a button using (change) detector? - html

I am trying to post data to my REST server. When I use a (change) it sends the data to my rest server. When I try to activate the method on my button it doesnt even try to make a POST call. How can I solve this problem? I can't find anything about it.
HTML file:
<div class="container py-5">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card rounded-0">
<div class="card-header">
<h3 class="mb-0">Organize</h3>
</div>
<div class="form-group">
<label for="codes" class="m-2">Choose a restaurant:</label>
<form #f="ngForm">
<input
type="text"
list="codes"
class="m-2"
(change)="saveCode($event)">
<datalist id="codes">
<option *ngFor="let c of codeList" [value]="c.name">{{c.name}}</option>
</datalist>
</form>
<button
type="submit"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
routerLink="/menu"
(change)="saveCode($event)"
>Aanmaken</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Typescript file:
// Method to post data to backend
public saveCode(e): void {
const name = e.target.value;
const list = this.codeList.filter(x => x.name === name)[0];
this.restaurant.name = list.name;
this.restaurant.address = list.address;
console.log(list.name);
console.log(list.address);
// Additional information to the server content type
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
// Making an array with the values of the restaurant
const data = {
name: list.name,
address: list.address
};
console.log(data);
// POST method
this.http.post('http://localhost:8080/aquadine-jee/resources/restaurant',
JSON.parse(JSON.stringify(data)) , httpOptions)
// wait till it gets posted to the backend
.subscribe( // subscribe to observable http.post
res => {
console.log("response" + " " + res); // log results otherwise log error
},
err => {
console.log('Error occured');
}
);
}
I tried to call the method by:
<button
type="submit"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
routerLink="/menu"
(change)="saveCode($event)"
>Aanmaken</button>
and:
<button
type="submit"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
routerLink="/menu"
(click)="saveCode($event)"
>Aanmaken</button>

In addition to the answer by #Moslem, change the button type from submit to button
<button type="button" .. > instead of <button type="submit" ...>

Conflict using routerLink routerLink="/menu" and click event.
change routing when back response.
Inject router: Router class and use this.router.navigateByUrl(url: string)
Router
constructor(private router: Router){
}
public saveCode(e): void{
// POST method
this.http.post('http://localhost:8080/aquadine-jee/resources/restaurant',
JSON.parse(JSON.stringify(data)) , httpOptions)
// wait till it gets posted to the backend
.subscribe( // subscribe to observable http.post
res => {
console.log("response" + " " + res); // log results otherwise log error
this.router.navigateByUrl("/menu")
},
err => {
console.log('Error occured');
}
);
}

Related

json object is not effecting to view

I am using angular Formio for dynamic screen creation, as part of that when I get the screen script from database, if I change the label of the particular element in ngOnInit() I am able to change.
but once the screen is displayed, then if I change the lable it is not effecting.
html
<Formio [form]="form" [submission]="submission" (submit)="onSubmit($event)"></formio>
<div class="mb-5">
<div class="row">
<div class="col-12 mb-5">
<div class="pull-right" style="float:right;">
<button class="btn save-button" (click)="clearData()">Clear data</button>
<button class="btn save-button" (click)="showData()">Show data</button>
</div>
</div>
</div>
</div>
component
ngOnInit() {
debugger;
this.triggerRefresh = new EventEmitter();
this.http.get('http://localhost:3000/angcomp/3')
.subscribe(
response => {
debugger;
this.data = response.json();
this.form = this.data;
this.form.components[0].label = 'Changed';//it is updating the lable in view
},
err => {console.error(err)}
);
}
showData() {
this.form.components[0].label = 'Again Changed'; // here it is not changing but in this.form.components[0].label value is displaying as 'Again Changed', but not effecting in front end
}
Try the refresh property in formio
In yout HTML:
<Formio [refresh]="triggerRefresh" [form]="form" [submission]="submission" (submit)="onSubmit($event)"></formio>
In your component:
showData() {
this.form.components[0].label = 'Again Changed';
this.triggerRefresh.emit({
form: this.form
});
}
https://github.com/formio/angular-formio/wiki/Form-Renderer#updating-forms-and-submissions

Why doesnt (click) sends my data inside <button>, but (change) inside <input> does in Angular, HTML

I want to send some data to my Glassfish RESTful server. When I use (change) inside the input tag it activates the method and succesfully sends the data, but when I use (click) or (change) to activate the method, it doesn't do anything. I tried to seperate the Sending data method and the router method, but to no avail.
How can I solve this?
html file:
<div class="container py-5">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card rounded-0">
<div class="card-header">
<h3 class="mb-0">Organize</h3>
</div>
<div class="form-group">
<label for="codes" class="m-2">Choose a restaurant:</label>
<form #f="ngForm">
<input
type="text"
list="codes"
class="m-2"
(change)="saveCode($event)"
>
<datalist id="codes">
<option *ngFor="let c of codeList" [value]="c.name">{{c.name}}</option>
</datalist>
<button
type="button"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
(click)="routerRed()"
>Aanmaken</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
typescript file:
import {Component, OnInit, ViewChild} from '#angular/core';
import {Router} from "#angular/router";
import {NgForm} from "#angular/forms";
import {HttpClient, HttpHeaders} from "#angular/common/http";
#Component({
selector: 'app-organize',
templateUrl: './sendinvite.component.html',
styleUrls: ['./sendinvite.component.css']
})
export class SendinviteComponent implements OnInit {
// public codeValue: string;
// List of restaurants
codeList = [
{ name: 'Mcdonalds', address: 'Kalverstraat 5' },
{ name: 'Kentucky Fried Chicken', address: 'Kalverstraat 4' },
{ name: 'Burger King', address: 'Kalverstraat 3' },
{ name: 'Dominos pizza', address: 'Kalverstraat 2' },
{ name: 'New York Pizza', address: 'Kalverstraat 1' }
];
// Assign empty value to id, name and address
#ViewChild('f', { static: true }) form: NgForm;
restaurant = {
name: ' ',
address: ' '
};
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'my-auth-token'
})
};
constructor(private http: HttpClient, private router: Router) {
}
ngOnInit() {
}
// Method to post data to backend
public saveCode (e): void {
const name = e.target.value;
const list = this.codeList.filter(x => x.name === name)[0];
this.restaurant.name = list.name;
this.restaurant.address = list.address;
console.log(list.name);
console.log(list.address);
// Additional information to the server content type
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
// Making an array with the values of the restaurant
const data = {
name: list.name,
address: list.address
};
console.log(data);
// POST method
this.http.post('http://localhost:8080/aquadine-jee/resources/restaurant',
JSON.parse(JSON.stringify(data)) , httpOptions)
// wait till it gets posted to the backend
.subscribe( // subscribe to observable http.post
res => {
console.log("response" + " " + res); // log results otherwise log error
},
err => {
console.log('Error occured');
}
);
}
routerRed(){
this.router.navigateByUrl('/menu');
}
I tried to use:
<button
type="submit"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
routerLink="/menu"
(change)="saveCode($event)"
>Aanmaken</button>
and:
<button
type="submit"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
routerLink="/menu"
(click)="saveCode($event)"
>Aanmaken</button>
The (change) event inside the button is going to do nothing, the (click) is more appropiate, but the $event passed inside the click event is going to return the information about the click itself (mouse position, etc).
What you should do is, whenever click is called, get the value of the form and send that to the saveData function. (Maybe by doing something like saveData(this.f.value), but I can't tell with certainty)
I don't have experience with template driven forms, maybe it's worth for you to take a look at Reactive Forms, it is going to make your life easier IMHO
The (change) event will not be triggered on the click of a button as there is no "change" as such. You should use (click) instead. The reason why your saveCode() is not being invoked when you set both routerLink and (click) is because of the routerLink. When you click the button, Angular is navigating to /menu before it triggers your click event. You can navigate from your component in your saveCode() instead.
Since you also have an API call in your saveCode(), it would probably be better if you navigate on success as it might not make sense to re-route the user if the API call fails (especially if the new route depends on the saved data)
Try this in your code.
HTML
<button type="submit"
class="btn btn-primary btn-lg float-none m-2"
id="btnAanmaken"
(click)="saveCode($event)">
Aanmaken
</button>
component
.subscribe( // subscribe to observable http.post
res => {
console.log("response" + " " + res); // log results otherwise log error
this.router.navigateByUrl('/menu');
},
err => {
console.log('Error occured');
});
Edit: Rather than using $event to pass your values to the component, you can make use of the ngForm you have used in your code along with ngModel.
component
<input type="text"
list="codes"
class="m-2"
name="restaurantName"
ngModel
>
component
#ViewChild('f', { static: true }) form: NgForm;
...
public saveCode (): void {
const name = this.form.value.restaurantName;
...
}
Here is another example from the documentation on how to bind values to the form using ngForm and ngModel

Dynamic Form issue with Reactive Form

I want to create a Dynamic input field on button press and successfully I am able to create new input field on button press with the help of reactive form but now I want to set predefined value in input field as per API data. Like if from API if I am getting 6 names, I want to create that 6 input fields on Init and then I want to able to new input field on button press. Here is my code which I tried, I am able to create new input field but not able create input fields as per API data on Init.
Component.ts
export class ScreenmodalComponent implements OnInit {
#Input() screendetails;
personalForm : FormGroup;
arrayItems: any = [];
screenList: string;
constructor(private activeModal: NgbActiveModal, private formbuilder: FormBuilder, private pagesService: PagesService, private utilService: UtilService) { }
ngOnInit() {
this.personalForm = this.formbuilder.group({
other: this.formbuilder.array([ this.addanotherForm()])
});
// Api call
this.pagesService.GetScreens('').then(res => {
console.log('get screens api', res);
for (let i = 0; i < res['data']['length']; i++) {
this.arrayItems = res['data'][i]['name'] //names which I want to set as input field value and generate input fields for every name
}
}).catch(error => {
this.utilService.showError('Something went wrong', 'Error');
console.log('err is', error);
});
}
addanother():void {
(<FormArray>this.personalForm.get('other')).push(this.addanotherForm());
}
addanotherForm(): FormGroup{
return this.formbuilder.group({
screenname: [''],
});
}
clear(i : number){
(<FormArray>this.personalForm.get('other')).removeAt(i);
}
onSubmit(): void {
console.log(this.personalForm.value);
}
closeModel() {
this.activeModal.close();
}
}
Componenent.html code
<div class="custom_modal pb-3">
<div class="modal-header border-0 p-1 pl-3 pr-3 d-flex justify-content-between align-items-center">
<h3 class="m-0">Project: {{screendetails.name}}</h3>
<button type="button" class="close" data-dismiss="modal" (click)="closeModel()">×</button>
</div>
<div class="modal-body p-3">
<div class="body_top d-flex justify-content-between mb-4 mt-2 align-items-center">
<h3 class="title m-0">Add Screens</h3>
</div>
<form [formGroup]="personalForm" (ngSubmit)="onSubmit()">
<div formArrayName="other" class="form-group" *ngFor="let other of personalForm.get('other').controls; let i = index" >
<div [formGroupName] = "i">
<div class="screen_row mb-4">
<div class="row">
<div class="col-md-3 col-sm-3 d-flex align-items-center">
<label>Screen Name</label>
</div>
<div class="col-md-8 col-sm-8 pl-0 pl-sm-3">
<input type="text" class="form-control rounded-0" formControlName="screenname" name="screenname">
</div>
<div class="col-md-1 col-sm-1 d-flex align-items-center justify-content-center pl-0 pl-sm-3">
<button type="button" class="close" (click)="clear(i)">×</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer border-0 d-table w-100">
<button type="button" class="btn-primary float-left" (click)="addanother()">Add New Screen</button>
<div class="float-right">
<button type="button" class="btn-primary mr-3" data-dismiss="modal" (click)="onSubmit();">Apply</button>
<button type="button" class="btn-primary cancle" data-dismiss="modal" (click)="closeModel()">Cancel</button>
</div>
</div>
</form>
</div>
</div>
This is my code. Please help me setting up by default input fields as per the number of names in API call.Thannk you
Normally, you change your function addAnotherForm to allow pass data
addanotherForm(data:any): FormGroup{
return this.formbuilder.group({
screenname: [data],
});
}
In your case you must change the function addanother
addanother(data:any):void {
(<FormArray>this.personalForm.get('other')).push(this.addanotherForm(data));
}
So, your ngOnInit can be like.
//at first an Empty FormArray
this.personalForm = this.formbuilder.group({
other: this.formbuilder.array([])
});
// Api call
this.pagesService.GetScreens('').then(res => {
console.log('get screens api', res);
for (let i = 0; i < res['data']['length']; i++) {
this.arrayItems = res['data'][i]['name']
this.addanother(res['data'][i]['name'] //fill the array
}
}).catch(error => {
this.utilService.showError('Something went wrong', 'Error');
console.log('err is', error);
});
Well, really you can simply all the code -and really you needn't this.arrayItems- and we use a map
this.pagesService.GetScreens('').then(res => {
this.personalForm=new FormGroup({
other:new FormArray(
res['data'].map(d>=>{
return new FormGroup({
screenname:new FormControl(d.name))
})
})
)
})
}).catch(error => {
this.utilService.showError('Something went wrong', 'Error');
console.log('err is', error);
});
NOTE: You needn't make a ForGroup if you only want yo control a FormArray, and your formArray can be only a formArray of formControls not a FormArray of FormGroup

How to send data from datalist in Angular to Rest api

I have a frontend project in Angular where I have a Html file with a datalist and another backend project Restful API
How do I get the selected option from the datalist in Angular and send the value to my rest server. I use Glassfish. I want to read it in JSON format.
Here is some code I already have and tried to use.
export class OrganizeComponent implements OnInit {
#ViewChild('f') form: NgForm;
restaurant = {
naam: '',
adres: ''
};
constructor(private router: Router, private http: HttpClient) { }
ngOnInit() {
}
onOrganize(form: NgForm) {
this.restaurant.naam = this.form.value.naam;
this.restaurant.adres = this.form.value.adres;
this.http.post('http://localhost:8080/testproject/resources/restaurant', {
naam: this.restaurant.naam,
adres: this.restaurant.adres})
.subscribe(
res => {
console.log(res);
},
err => {
console.log('Error occured');
}
);
}
btnClick1= function () {
this.router.navigateByUrl('/menu');
};
<div class="form-group">
<div class="card-body">
<form
(ngSubmit)="onOrganize(f)"
#f="ngForm">
<label for="restaurants">Choose a restaurant:</label>
<input list="restaurantList" id="restaurants" ngModel name="naam"/>
<datalist id="restaurantList" name="naam">
<option id="mcdonalds" name="naam" type="text">Mcdonalds</option>
<option id="kentuckyfriedchicken" name="naam">Kentucky Fried Chicken</option>
<option id="burgerking" name="naam">Burger King</option>
<option id="dominospizza" name="naam">Domino's pizza</option>
</datalist>
<div class="form-group">
<label>Address</label>
<input
type="text"
class="form-control form-control-lg rounded-0"
ngModel
name="adres"
required
address>
</div>
<button type="submit"
class="btn btn-primary btn-lg float-right"
[disabled]="!f.valid" (click)="btnClick1();">Make
</button>
</form>
</div>

Use same input text for two button using ASP.NET MVC

I want to use the same text to go different View.At present I set two view one is PlaceInformation and another is Google Map View. How can I set condition to go both View using HTML Beginfrom.I want to use #using (Html.BeginForm("GoogleMapView", "Home")) here. My Code sample is look like this-
#using (Html.BeginForm("PlaceInformation", "Home"))
{
<div class="wrapper wrapper-content">
<div class="row">
<div class="col-sm-12">
#Html.TextBoxFor(m =>m.Name)
<label for="somevalue">City Name</label>
<div class="input-group-btn">
<button class="btn btn-lg btn-primary" type="submit">Search</button>
</div>
<div class="input-group-btn">
<button class="btn btn-lg btn-primary" type="submit">Map View</button>
</div>
</div>
</div>
</div>
}
This is how i modified code .But it is not working.
<form id="myForm">
<div class="wrapper wrapper-content">
<div class="row">
<div class="col-sm-12">
#Html.TextBoxFor(m => m.Name)
<label for="somevalue">City Name</label>
<div class="input-group-btn">
<button id="searchBtn" class="btn btn-lg btn-primary" type="submit">Search</button>
</div>
<div class="input-group-btn">
<button id="mapViewBtn" class="btn btn-lg btn-primary" type="submit">Map View</button>
</div>
</div>
</div>
</div>
<script> {
$("#searchBtn").on("click", function (event) {
event.preventDefault();
$.ajax({
type: "POST",
url: '/home/placeinformation',
data: $("#myForm").serialize(), // serializes the form's elements.
success: function (data) {
//here you will get the result from the Controllers, like a partial view or you can do a redirect to another view if form post is successful.
},
error: function (xhr, status, error) {
//Handle any errors here
}
});
});
}
</script>
<script>{
$("#mapViewBtn").on("click", function (event) {
event.preventDefault();
$.ajax({
type: "POST",
url: '/home/GoogleMap',
data: $("#myForm").serialize(), // serializes the form's elements.
success: function (data) {
//here you will get the result from the Controllers, like a partial view or you can do a redirect to another view if form post is successful.
},
error: function (xhr, status, error) {
//Handle any errors here
}
});
});
}
</script>
My Controller for GoogleMap is-
public ActionResult GoogleMap(City objCityModel)
{
string name = objCityModel.Name;
ViewBag.Title = name;
var ReadJson = System.IO.File.ReadAllText(Server.MapPath(#"~/App_Data/POI_Json/" + name + ".json"));
RootObject json = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<RootObject>(ReadJson);
List<Poi> mycities = new List<Poi>();
foreach (var item in json.poi)
{
Poi obj = new Poi()
{
Name = item.Name,
Shorttext = item.Shorttext,
GeoCoordinates = item.GeoCoordinates,
Images = item.Images,
};
mycities.Add(obj);
}
ViewBag.Cities = mycities;
return View();
}
For Getting the name-
[HttpPost]
public ActionResult Index(City objCityModel)
{
string name = objCityModel.Name;
return View();
}
in My PLace information I am using the same data as GoogleMap view
public ActionResult PlaceInformation(City objCityModel)
{
string name = objCityModel.Name;
ViewBag.Title = name;
var ReadJson = System.IO.File.ReadAllText(Server.MapPath(#"~/App_Data/POI_Json/" + name + ".json"));
RootObject json = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<RootObject>(ReadJson);
List<Poi> mycities = new List<Poi>();
foreach (var item in json.poi)
{
Poi obj = new Poi()
{
Name = item.Name,
Shorttext = item.Shorttext,
GeoCoordinates = item.GeoCoordinates,
Images = item.Images,
};
mycities.Add(obj);
}
ViewBag.Cities = mycities;
return View();
}
This will only generate one html form and it is the form element that decides where the form is posted. In other words there is no way to post this form to different controller actions depending on the button being clicked. However, there are of course other ways. I would bind and post the two post buttons with jQuery like this:
Change .cshtml to this:
<form id="myForm">
#Html.TextBoxFor(m => m.Name)
<label for="somevalue">City Name</label>
<div class="input-group-btn">
<button id="searchBtn" class="btn btn-lg btn-primary" type="submit">Search</button>
</div>
<div class="input-group-btn">
<button id="mapViewBtn" class="btn btn-lg btn-primary" type="submit">Map View</button>
</div>
</form>
Add id to the buttons:
<div class="input-group-btn">
<button id="searchBtn" class="btn btn-lg btn-primary" type="submit">Search</button>
</div>
<div class="input-group-btn">
<button id="mapViewBtn" class="btn btn-lg btn-primary" type="submit">Map View</button>
</div>
script:
$("#searchBtn").on("click", function (event) {
event.preventDefault();
$.ajax({
type: "POST",
url: '/home/placeinformation',
data: $("#myForm").serialize(), // serializes the form's elements.
success: function (data) {
//here you will get the result from the Controllers, like a partial view or you can do a redirect to another view if form post is successful.
},
error: function (xhr, status, error) {
//Handle any errors here
}
});
});
}
second script (I changed the button you bind to and the controller action you want to call.
$("#mapViewBtn").on("click", function (event) {
event.preventDefault();
$.ajax({
type: "POST",
url: '/home/urlToTheOtherAction,
data: $("#myForm").serialize(), // serializes the form's elements.
success: function (data) {
//here you will get the result from the Controllers, like a partial view or you can do a redirect to another view if form post is successful.
},
error: function (xhr, status, error) {
//Handle any errors here
}
});
});
}