Why Vue doesn't show data from my WebApi with axios and params? - asp.net-web-api

i am practicing with axios and Vue in the use of WebApi.
I have done this:
My template:
<template>
<form>
<div>
<div class="panel panel-default">
<div class="panel-heading"><h1><strong>Lista de nombres</strong></h1></div>
<div class="panel-body">
<table class="table table-hover table-bordered table-striped">
<thead>
<tr>
<th>Nombre</th>
<th>Apellido Paterno</th>
<th>Apellido Materno</th>
</tr>
</thead>
<tbody>
<tr v-for="usuario in usuarios">
<td>{{usuario.Nombre}}</td>
<td>{{usuario.Apellido_P}}</td>
<td>{{usuario.Apellido_M}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<br />
<p>Buscar usuario</p>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" v-model="busqueda" placeholder="Buscar usuario" />
<button type="submit" class="btn btn-default" v-on:click="buscarUsuario">Buscar</button>
</div>
</div>
</div>
</form>
</template>
And My Script:
<script>
import axios from 'axios'
export default {
data() {
return {
usuarios:[],
busqueda: ''
}
},
methods: {
buscarUsuario() {
axios.get('http://localhost:50995/api/GetUsuario', {
params: {
'id' : 7
}
}).then(response => {
this.usuarios = response.data
}).catch(e => {
console.log(e)
})
},
getUsuarios() {
axios.get("http://localhost:50995/api/GetUsuarios")
.then(response => {
this.usuarios = response.data
})
.catch(e => {
this.errors.push(e)
})
}
},
created() {
this.getUsuarios(),
this.buscarUsuario()
}
}
</script>
The method getUsuarios() is working well; but the method buscarUsuario() not; only if i put in the params ‘id’ a number the log of my WebApi records a query, but if write this code: this.busqueda not working. Either way, the result in the page is not working with the method buscarUsuario().
And finally friends, how to prevent load the page everytime i push the button?
Thank you very much!

It seems kind of strange. I conclude you reading it properly on server-side. So I bet your server only wants Number(7) not String(7). You should change basic stance of busqueda to null. Then add .number modifier to v-model. Like that:
<input type="text" class="form-control" v-model.number="busqueda" placeholder="Buscar usuario" />
How to prevent load the page everytime you push button?
Add .prevent modifier.
Change:
<button type="submit" class="btn btn-default" v-on:click="buscarUsuario">Buscar</button>
To:
<button type="submit" class="btn btn-default" v-on:click.prevent="buscarUsuario">Buscar</button>
Also I recomend use # as shortcut for v-on:(in this example you could have use #click.prevent).
If it still refreshes. Add #submit.prevent="functionName" to form...

Use id without quote and click.prevent to prevent submit.
params: {
id: 7
}
<button type="submit" class="btn btn-default" v-on:click.prevent="buscarUsuario">Buscar</button>
also you can use button type="buttton"
<button type="button" class="btn btn-default" v-on:click="buscarUsuario">Buscar</button>

Related

Add and Remove dom elements using alpine JS

I am trying to build a custom add and remove entire div element from an array using alpine JS, here is my code which is working but instead of removing from the exact remove button click it will remove the last one on the array.
HTML
<div x-data="addRemove()">
<template x-for="(field, index) in fields" :key="index">
<div>
<input type="text" name="txt1[]" class="form-input">
<button type="button" class="btn btn-danger btn-small" #click="removeField(index)">×</button>
</div>
</template>
<button type="button" #click="addNewField()">+ Add Row</button>
</div>
JAVASCRIPT
return {
fields: [],
addNewField() {
this.fields.push({});
},
removeField(index) {
this.fields.splice(index, 1);
}
}
Found a solution, this is what I did.
HTML
<div x-data="addRemove()">
<template x-for="(field, index) in fields" :key="field.id">
<div>
<input type="text" name="txt1[]" class="form-input">
<button type="button" class="btn btn-danger btn-small" #click="removeField(field)">×</button>
</div>
</template>
<button type="button" #click="addNewField()">+ Add Row</button>
</div>
JAVASCRIPT
function addRemove() {
return {
fields: [],
addNewField() {
this.fields.push({id: new Date().getTime() + this.fields.length});
},
removeField(field) {
this.fields.splice(this.fields.indexOf(field), 1);
}
}
}
You've to set the 'key' with a unique value in the looping.
<div x-data="{data: []}">
<div #click="data.push({ randomNumber: new Date().getTime()})">(Click Here To Add New Data)</div>
<template x-for="(item, index) in data" :key="index">
<div>
<span x-text="item.randomNumber"></span>
<span #click="data.splice(index, 1)">Remove</span>
</div>
</template>
</div>
online test: https://codepen.io/yuxufm/pen/YzLoxvE

Spring MVC Controller not receiving atribute from Template with Thymeleaf

I have a template which represents a list of notes that are retrieved from a database
<tr th:unless="${#lists.isEmpty(allNotes)}"
th:each="note : ${allNotes}">
<td>
<form action="#" method="POST" th:action="#{/home/editNote}"
th:object="${note}">
<input type="hidden" id="noteId" name="noteId" th:value="*{noteId}">
<button type="button" class="btn btn-success"
onclick="editNoteModal('updateNote', this.getAttribute('data-noteId'),
this.getAttribute('data-noteTitle'),
this.getAttribute('data-noteDescription'))">Edit
</button>
</form>
<form action="#" method="POST" th:action="#{/home/deleteNote}">
<input type="hidden" name="noteId" th:value="*{note.noteId}">
<a class="btn btn-danger">Delete</a>
</form>
</td>
<th scope="row" th:text="${note.noteTitle}">Example Note Title</th>
<td th:text="${note.noteDescription}">Example Note Description</td>
</form>
</tr>
</tbody>
In the GUI It looks like this
This is my modal code which should open after I click on the edit button:
<div class="modal fade" id="editNoteModal" tabindex="-1" role="dialog" aria-labelledby="noteModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editnoteModalLabel">Note</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="note-title" class="col-form-label">Title</label>
<input type="text" name="noteTitle" class="form-control" id="editNoteTitle"
maxlength="20" required>
</div>
<div class="form-group">
<label for="note-description" class="col-form-label">Description</label>
<textarea class="form-control" name="noteDescription" id="editNoteDescription"
rows="5" maxlength="1000" required></textarea>
</div>
<button id="editNoteSubmit" type="submit" class="d-none"></button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="$('#editNoteModal').click();">
Save
changes
</button>
</div>
</div>
</div>
</div>
</div>
In the GUI it looks like this:
I want to be able to edit given note and then send the edited id to the controller so I can update this change within the database. I have correct database logic for the update, I just don't know the way how to send the given notes id and changed information to my controller.
#PostMapping("/editNote")
public String editNote(#ModelAttribute(value = "note") Note note,
#ModelAttribute(value = "noteId") NoteIdModel noteIdModel, Model model,
Authentication authentication) {
System.out.println("noteid " + note.getNoteId());
System.out.println("noteidHidden " + noteIdModel.getNoteIdHidden());
System.out.println("notedesc" + note.getNoteDescription());
noteService.editNote(note, authentication);
return "result";
}
However, the incoming noteId is null. I have checked the database and the note with correct id is indeed in the database and is also retrieved from the database. It's just not sent to the controller.
Try this one:
HTML fragment
<tr th:unless="${#lists.isEmpty(allNotes)}"
th:each="note : ${allNotes}">
<td>
<button type="button" class="btn btn-success"
th:data-noteId="${note.noteId}"
th:data-noteTitle="${note.noteTitle}"
th:data-noteDescription="${note.noteDescription}"
onclick="editNoteModal('updateNote', this.getAttribute('data-noteId'),this.getAttribute('data-noteTitle'),this.getAttribute('data-noteDescription'))">Edit
</button><br/>
<a class="btn btn-danger">Delete</a>
</td>
<td scope="row" th:text="${note.noteTitle}"></td>
<td th:text="${note.noteDescription}"></td>
</tr>
JS fragment
/**
* Fill edit modal with current information
*/
function editNoteModal(modal, noteId, noteTitle, noteDescription) {
$('#editnoteModalLabel').text("Note " + noteId);
$('#editNoteId').val(noteId);
$('#editNoteTitle').val(noteTitle);
$('#editNoteDescription').val(noteDescription);
$('#editNoteModal').modal("show");
}
/**
* Save to backend edit information
*/
function save() {
var noteId = $('#editNoteId').val();
var noteTitle = $('#editNoteTitle').val();
var noteDescription = $('#editNoteDescription').val();
$.ajax({
url : "./editNote",
method : "POST",
headers : {
'Content-Type' : 'application/json'
},
data : JSON.stringify({
noteId : noteId,
noteTitle : noteTitle,
noteDescription : noteDescription
}),
success : function(result) {
$('#editNoteModal').modal("hide");
alert(result);
}
})
}
Backend
#PostMapping(path = "/editNote", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> editNote(#RequestBody Note note) {
System.out.println("noteid " + note.getNoteId());
System.out.println("noteidTitle " + note.getNoteTitle());
System.out.println("notedesc" + note.getNoteDescription());
//Save in database
return ResponseEntity.ok("OK");
}
This is how I did while I was trying to pass the id to open a modal by finding details using that id:
<a href="#" class="btn btn-sm btn-primary"
th:data-parameter1="${user.useruuid}"
onclick="openUserModal(this.getAttribute('data-parameter1'));">Details</a>
And then somewhere in your JavaScript, you can something (similar) like this:
<script type="text/javascript" th:fragment="includeModalScript">
function openUserModal(id) {
$.ajax({
url: "/findOnebyId?id="+ id,
success: function(data){
alert(id);
.......
</script>
And my controller looked like this:
#GetMapping("/findOnebyId")
#ResponseBody
public AppUser findOneByUUID(String id) {
....
}
You can take a look here, here and here for a working demo similar to your issue/requirement.

Vue js select box giving a couple of errors

I'm doing a site that uses laravel and vue js. The error I'm getting is this
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "selected_parent"
and this
[Vue warn]: Error in v-on handler (Promise/async): "Error: Request failed with status code 404"
I can't see where I'm going wrong.
Here is my product.blade.php
#extends('layouts.public')
#section('content')
<div class="content_wrapper">
#foreach($single_product as $product)
<div class="row single_product_wrapper">
<div class="col-lg-8 col-md-12-col-sm-12 product_details">
#foreach($parent_product as $parent)
<h1>
{{ $parent->title }}
</h1>
<table style="width: 100%; height: 95px;" border="2" cellspacing="5" cellpadding="5">
<tbody>
<tr style="text-align: center;">
<td>
<strong>Code</strong>
</td>
<td>
<strong>Description</strong>
</td>
<td>
<strong>Price</strong>
</td>
</tr>
<tr style="text-align: center;">
<td>
{{ $parent->code }}
</td>
<td>
{{ $parent->description }}
</td>
<td>
{{ $parent->price }}
</td>
</tr>
</tbody>
</table>
#endforeach
<!-- BEGIN ADD TO CART FORM -->
<div id="app">
#foreach($parent_product as $parent)
<code-selection :products="{{ $parent_product }}" :children="{{ $parent->parent }}"></code-selection>
#endforeach
</div>
<!-- END ADD TO CART FORM -->
</div>
</div>
#endforeach
</div>
#stop
and this is my vue
<template>
<div>
<form #submit.prevent="submit">
<div class="row">
<div class="col-lg-12 code_select">
<select name="code" id="code" class="form-control mb-2 mt-10" v-model="selected_parent" required>
<option :value="selected_parent">Please select your code</option>
<option v-for="product in products" :value="product.id">
{{ product.code }}
</option>
<option v-for="child in children" :value="child.id">
{{ child.code }}
</option>
</select>
</div>
</div>
<input type="submit" class="btn btn-dark btn-lg btn-block" value="Add To Cart">
</form>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: [
'products',
'children',
'selected_parent'
],
mounted() {
console.log('Component mounted.')
},
methods: {
submit(){
var formData = new FormData();
formData.append('code', this.selected_parent);
return axios.post('/add-to-cart/'+this.selected_parent, formData)
.then(
function(response)
{
console.log(response.data.redirect);
window.location = response.data.redirect;
}
);
},
},
}
</script>
So what I would like to happen is, when the user selects a code and hits the Add To Cart button they will then get taken to the cart page, but right now
that isn't happening when I select the code and hit the button nothing happens and I get the errors that I said in my console.
If there is anything else you need to know please let me know
The answer is simple, you should break the direct prop mutation by assigning the value to some local component variables(could be data property, computed with getters, setters, or watchers).
Here's a simple solution using the watcher.
<template>
<input
v-model="input"
#input="updateInput" />
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
},
data() {
return {
input: '',
};
},
watch: {
value: {
handler(after) {
this.input = after;
},
immediate: true,
},
},
methods: {
updateInput() {
this.$emit('input', this.input);
},
},
};
</script>
It's what I use to create any data input components and it works just fine. Any new variables sent by parent v-model will be watched and assigned to the input variable and once the input is received, catch that action and emit input to parent suggesting that data is input from the form element.
And for the second part, when you receive the new url from redirect, simply replace the location href like this:
return axios.post('/add-to-cart/'+this.selected_parent, formData)
.then((response) => {
window.location.href = response.data.redirect;
})
.catch((error) => {
console.log(error);
})
);

Child component mounts faster than parent

I use Laravel and Vue. I have two components: parent and child.
Parent:
<template>
<div>
<sport-sites-add :applications-all-list="applicationsAll"></sport-sites-add>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Application id</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col">Picture</th>
<th scope="col">URL</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="sportSite in sportSites">
<th scope="row">{{ sportSite.id }}</th>
<td>
<template v-for="application in sportSite.applications">
id {{ application.id }} => {{ application.name }} <br>
</template>
</td>
<td>{{ sportSite.name }}</td>
<td>{{ sportSite.description }}</td>
<td>
<img style="width: 100px; height: 100px;" :src="sportSite.image" >
</td>
<td>
<a :href="sportSite.url" target="_blank">{{ sportSite.url }}</a>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { EventBus } from '../../app';
export default {
name: "SportSitesTable",
mounted(){
this.loadTable();
this.getApplications();
},
methods:{
loadTable: function () {
window.axios.get('/sport_sites_all')
.then(resp => {
this.sportSites = resp.data.data;
}).catch(err => {
console.error(err);
});
},
getApplications: function () {
window.axios.get('/applications/all')
.then(resp => {
this.applicationsAll = resp.data.applications.data;
}).catch(err => {
console.error(err);
});
}
},
data(){
return {
sportSites: [],
applicationsAll: [],
}
},
}
</script>
Child:
<template>
<div>
<button type="button" class="btn btn-primary my-2" data-toggle="modal" data-target="#sportSiteAdd">
Add
</button>
<div class="modal fade" id="sportSiteAdd" tabindex="-1" role="dialog" aria-labelledby="sportSiteAddLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="sportSiteAddLabel">Add sport site</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ul class="alert-danger">
<li v-for="error in errors">
{{ error[0] }}
</li>
</ul>
<form>
<div class="form-group">
<label for="name">Title</label>
<input type="text" class="form-control" id="name" name="name" v-model="formFields.name">
</div>
<div class="form-group">
<label for="image">Picture</label>
<input type="text" class="form-control" id="image" name="image" v-model="formFields.image">
</div>
<div class="form-group">
<label for="url">URL</label>
<input type="text" class="form-control" id="url" name="url" v-model="formFields.url">
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea class="form-control" id="description" name="description" v-model="formFields.description"></textarea>
</div>
<div>
<label class="typo__label">Applications </label>
<multiselect v-model="formFields.applications"
tag-placeholder="Applications"
placeholder="Search"
label="name"
track-by="id"
:options="applications"
:multiple="true"
:taggable="true">
</multiselect>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" v-on:click="submit">Save</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { EventBus } from '../../app';
import Multiselect from 'vue-multiselect'
export default {
name: "SportSitesAdd",
props: ['applicationsAllList'],
methods:{
submit: function (e) {
window.axios.post('/sport_site/add/', this.formFields)
.then(res => {
console.log('Saved!');
$('#sportSiteAdd').modal('hide');
this.formFields.name = '';
this.formFields.image = '';
this.formFields.url = '';
this.formFields.description = '';
EventBus.$emit('reloadApplicationsTable');
}).catch(err => {
if(err.response.status === 422){
this.errors = err.response.data.errors || [];
}
console.error('Error of saving!');
});
},
},
data(){
return {
formFields: {
name: '',
image: '',
url: '',
description: '',
applications: this.applicationsAllList,
},
errors: [],
}
},
components: {
Multiselect
},
}
</script>
The parent component is a table. Child component is a form for the table. I pass a data from the parent to the child via props:
<sport-sites-add :applications-all-list="applicationsAll"></sport-sites-add>
In the child component I have a plugin for creating a multiple select. The plugin requires 'options' and 'values' collections. It's very simple, documentation with my case is here https://vue-multiselect.js.org/#sub-tagging. At the result I want to see the following: all items on the select are selected. But I have just the empty collection during mounting of the child component. I have available items on the 'select' but I dont know how I can make it selected by default. Obviously, I need to copy the applicationsAllList into local data() of child component and use it. But it not available during mounted and beforeMounted.
console.log tells me that the child is faster.
you're missing #tag function & v-model, in this case, must be array, You need to use applicationsAllList props directly on options
<multiselect v-model="formFields.value"
tag-placeholder="Applications"
placeholder="Search"
label="name"
track-by="id"
:options="applicationsAllList"
:multiple="true"
#tag="addTag"
:taggable="true">
</multiselect>
in methods add addTag function and add value as array
data() {
return {
formFields: {
name: '',
value: [],
image: '',
url: '',
description: '',
},
errors: [],
}
},
methods: {
addTag (newTag) {
const tag = {
name: newTag,
code: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
}
this.options.push(tag)
this.value.push(tag)
}
}

Fetch Records in Angular datatable

Im new to Angular and My Requirement is
A component includes a form with the field name call "Brand" and a button to add the same record to database through angular service and there should be a datatable which is fetching all brand data from database to data table.
so by using fetchall method in ts file, i am assigning values to data table. im calling fetchall method to ngoninit() which helps me to show the data in table while component get initialized. to add record, i am using a method call addyear() and calling the same method to onSumbit(). my problem is when i add the record to database, i should be able to load newly added record to angular data table! since that method in ngoninit(), i have to refresh the browser to get the record in data table kindly give me a solution. for the back end, im using Spring boot with Postgres database
My Component TS file
constructor(private brandService:BrandService,private toastyService: ToastyService) { }
ngOnInit() {
this.findbrand();
}
onSubmit()
{
this.saveBrand();
this.submitted=true;
}
saveBrand()
{
this.brandService.addbrand(this.brand).subscribe
(data=>this.addToast({title:'Record Has been added Successfully', msg:'', timeout: 5000, theme:'default', position:'top-right', type:'success'}),
error=>this.addToast({title:'Record Not Added! Sorry', msg:'', timeout: 5000, theme:'default', position:'top-right', type:'error'}));
this.brand=new Brand();
}
findbrand()
{
this.brandService.findbrand().subscribe(data=>this.data=data,error=>this.addToast({title:'Record Cannot be found! Sorry', msg:'', timeout: 5000, theme:'default', position:'top-right', type:'error'}));
}
My Service.TS file
export class BrandService {
constructor(private http:HttpClient) { }
private baseUrl='http://localhost:8080/snazzy-engine/brand';
addbrand(brand:object):Observable<any>
{
return this.http.post(`${this.baseUrl}` + `/insert`, brand,{
headers: {'schemaName':'test.'}
});
}
findbrand():Observable<any>
{
return this.http.get(`${this.baseUrl}` + `/find-all`,{
headers: {'schemaName':'test.'}
});
}
getbrandid(id: number): Observable<Object> {
return this.http.get(`${this.baseUrl}/find-one/${id}`, {headers:
{'schemaName':'test.'}});
}
}
My HTML File
<div class="table-content crm-table">
<div class="project-table">
<div id="crm-contact" class="dt-responsive">
<div class="row">
<div class="col-xs-12 col-sm-12 col-sm-12 col-md-6">
<div>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-6">
<div style="text-align: right;">
<label>Search:
<input type="search" [(ngModel)]="filterQuery" class="form-control input-sm full-data-search" placeholder="Search name">
</label>
</div>
</div>
</div>
<!-- <div class="panel-heading">User information</div>-->
<div class="table-responsive">
<table class="table table-bordered table-hover table-sm" [mfData]="data | dataFilter : filterQuery" #mf="mfDataTable" [mfRowsOnPage]="rowsOnPage" [(mfSortBy)]="sortBy"
[(mfSortOrder)]="sortOrder">
<thead class="thead-dark text-center">
<tr>
<th style="width:10%">
<mfDefaultSorter by="brandId">Brand ID</mfDefaultSorter>
</th>
<th style="width:70%">
<mfDefaultSorter by="name">Brand Name</mfDefaultSorter>
</th>
<th style="width:10%">
<mfDefaultSorter by="more">More</mfDefaultSorter>
</th>
<th style="width:10%">
<mfDefaultSorter by="checkbox">Delete</mfDefaultSorter>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of mf.data; let i = index;">
<td>{{item.brandId}}</td>
<td>{{item.brand}}</td>
<td class="action-icon">
<button type="button" class="btn btn-sm btn-primary" (click)="findybrandid(item.brandId);modalDefault.show();">
edit
</button>
</td>
<td>
<div class="checkbox text-center">
<label><input type="checkbox" value=""></label>
</div>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="10">
<mfBootstrapPaginator class="pagination-main f-right"></mfBootstrapPaginator>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<div style="text-align:center;">
<button class="btn btn-out btn-danger ripple light"><i class="icofont icofont-check-circled"></i>Delete</button>
</div>
</div>
</div>
</div>
try this
saveBrand()
{
this.brandService.addbrand(this.brand)
.subscribe(
data => this.addToast(
{
title:'Record Has been added Successfully',
msg:'',
timeout: 5000,
theme:'default',
position:'top-right',
type:'success'
}),
error => this.addToast(
{
title:'Record Not Added! Sorry',
msg:'',
timeout: 5000,
theme:'default',
position:'top-right',
type:'error'
})
);
this.data.push(this.brand); /*change: push new data into an array*/
this.brand=new Brand();
}

Resources