How to edit particular row in a table by popping a form modal in vuejs? - html-table

I am using a modal form to add new details to the row of a table. After adding details, I’m just adding edit and delete buttons at the end of it. Now here delete button is working fine. How to edit a row of a table by popping replicate of form modal by clicking “edit” button in a row.
Here’s my code:
<div class="layout-padding">
<div
class="item item-link"
v-for="modal in types"
#click="$refs[modal.ref].open()"
>
<i class="item-primary">add</i>
<div class="item-content has-secondary">
<div>{{modal.label}}</div>
</div>
</div>
</div>
<q-modal ref="maximizedModal" class="minimized" :content-css="{padding: '50px'}">
<div class="main">
<label>Enter Your Name:</label>
<input id="name" name="name" type="text" placeholder="Enter your Name" v-model="YourName">
<br>
<label>I am:</label>
<input type="radio" id="Male" value="male" v-model="picked">
Male
<input type="radio" id="Female" value="female" v-model="picked">
Female
<br>
<div class="button">
<button class="red" #click="$refs.maximizedModal.close()">Close</button>
<button class="blue" v-on:click="sub" #click="$refs.maximizedModal.close()">Submit</button>
</div>
</div>
</q-modal>
<table>
<thead>
<th>Name</th>
<th>Gender</th> </thead>
<tbody class="result">
<tr v-for="(h, index) in final">
<td v-for="(value, key, index) in h">
{{ value }}
</td>
<td><button id="edit" class="green edit" v-for="modal in types"
#click="ed(h, index);$refs[modal.ref].open()" type="submit">EDIT</button></td>
<td><button id="delete" class="red delete" v-on:click="del(index)" type="submit">Delete</button></td>
</tr>
</tbody>
</table>
And my script is:
export default {
data () {
return {YourName: '',
details: [],
final: [],
types: [
{
label: 'Add Details',
ref: 'maximizedModal'
}
],
position: 'bottom'
}
},
methods: {
sub: function () {
this.details = {
'name': this.YourName,
'gender': this.picked,
}
this.ed()
if (index === '[object MouseEvent]') {
this.final.push(this.details)
}
if (index > -1) {
this.final.splice(index, 1, this.details)
}
else {
alert('else')
alert(JSON.stringify(this.details))
this.final.push(this.details)
}
},
del: function (index) {
this.$delete(this.final, index)
},
ed: function (details, index) {
return index
}
}
}
If edit button is clicked, the same row should be edited. I don’t know how to proceed further. Please, guide me.

Using the 'splice' can able to modify the given array of object.
Can simply include this inside an 'if' loop:
this.final.splice(this.indi, 1, this.details)

Related

Unable to set the value to the first input field using id of the field - in vue

I have an input field and a button (when clicked on displays a dropdown with few items) when selecting the items it has to be shown on the first input field. Similarly when clicking on the 2nd button where the dropdown is shown the selected value is shown in the 2nd input field. This entire runs in a for loop , which is where I am facing the problem.
<tr v-for="items in itemList">
<td valign="top"> {{items}} </td>
<td align="left" nowrap>
<input v-model="itemCode" type="text" :id="'item_code_'+items"
#input="handleInput"
size="20" maxlength="27"
autocomplete="off">
<br/>
</td>
<td align="left" nowrap>
<a id="myDropdown" class="dropdown" style="text-decoration:none;font-
size:10pt; padding-left: 10px;padding-right: 10px;"
#click="loadFavs()"
href="javascript:void(0)" title="Click to choose an item from your
favorites">
<img hspace="3" alt="Favorites" src="/images/icons/LoadFav.png"
height="16" width="16"
onmousemove="this.style.cursor='pointer'"
:id="'bd_fav_image_' + items" title="Click to choose an item from
your favorites">
<select class="dropdown-content" v-if="showFav" name="BOMList"
:id="'bd_list_'+items" style="font-size:10pt;width: 100%" v-
model="selected" #change="selectingFav(items)">
<option value=""></option>
<option v-for="(fav,index) in favList" :id="index" v-
bind:value="fav" :key="fav" v-bind:index="index">{{fav}}
{{index}}</option>
</select>
</a>
</td>
<td valign="top" nowrap >
<input type="Text"
:id="'bd_qty_ '+ index"
value="" size="2"
inputmode="numeric"
maxlength="">
</td>
</tr>
favList--> this list holds a list of items , For eg:- A,B,C,D
When I select A it has to be shown in the input field.
selectingFav: function(value) {
console.log("Inside the selectingFav..." + this.selected + "value is ." +value);
setTheValue(value);
}
function setTheValue(val){
console.log("Inside the setThevlaue");
if (val === 1 ){
console.log("inside the if");
$j('#item_code_1').val(this.selected);
console.log("inside the if witht the value " + $j('#item_code_1').val());
}
Tried setting the value based on the id of the input field but nothing is showing up.
If I set the v-model to the input field then all the 3 fields will be showing up the same value.
Can someone please let me know what is the issue. Hope these details are sufficient.
a) v-model is internally implemented as:
<input v-model="myval">
<!-- is --!>
<input :model-value="myval" #update:model-value="v => myval = v">
so you can freely define your own function
<input v-for="obj, ind of whatever" #update:model-value="v => myfn(v, obj, ind)">
b) same as you have an array you v-for on you may make a parallel array
// you get the idea
data: () => ({ imputs: entries.map(e => 0) })
<div v-for="entry, ind of imputs">
<Whatever :entry="entry"/>
<imput v-model="imputs[ind]">
</div>
c) keep your imputs in objects, generally the best choice
// you get the idea
data: () => ({ imputs: entries.map(e => ({ entry: e, input: 0 })) })
// or
computed: {pairs(){ return this.entries.map(e => ({ entry: e, input: 0 })) }}
<div v-for="item of imputs">
<Whatever :entry="item.entry"/>
<imput v-model="item.input">
</div>
Here is how you can achieve that.
data() {
return {
itemList: [
{ id: 1 , value: '' },
{ id: 2, value: '' },
{ id: 3, value: '' }
]
}
},
methods:{
selectingFav: function(value) {
// value holds the index
if (value === 1 )
this.itemList[0].value = this.selected;
else if(value === 2 )
this.itemList[1].value = this.selected;
else
this.itemList[2].value = this.selected;
}
}
}
In HTML template section
<tr v-for="(items,i) in itemList">
<td valign="top"> {{items.id}} </td>
<td align="left" nowrap>
<input v-model="items.value" type="text" :id="'item_code_'+items"
#input="handleInput" size="20" maxlength="27" autocomplete="off">
<br/>
</td>

Failed to compile in vue.js browser error

I got stuck into an error that shows in the browser
Failed to compile.
./src/services/produtos.js Module Error (from
./node_modules/eslint-loader/index.js):
C:\Users\romul\Vue Projects\produto-client\src\services\produtos.js
9:13 error 'produto' is defined but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)
I´m following a tutorial on the internet but i can´t find what is wrong.
Here´s the produtos.js code
import {http} from './config'
export default {
listar:() => {
return http.get('produtos')
},
salvar:(produto) => {
return http.post('produto')
}
}
And here is the App.vue
<template>
<div id="app">
<template>
<div id="app">
<nav>
<div class="nav-wrapper blue darken-1">
Produtos Front
</div>
</nav>
<div class="container">
{{produto.nome}}
<form>
<label>Nome</label>
<input type="text" placeholder="Nome" v-model="produto.nome" />
<label>Quantidade</label>
<input type="number" placeholder="QTD" v-model="produto.quantidade" />
<label>Valor</label>
<input type="text" placeholder="Valor" v-model="produto.valor" />
<button class="waves-effect waves-light btn-small">
Salvar
<i class="material-icons left">save</i>
</button>
</form>
<table>
<thead>
<tr>
<th>NOME</th>
<th>QTD</th>
<th>VALOR</th>
<th>OPÇÕES</th>
</tr>
</thead>
<tbody>
<tr v-for="produto of produtos" :key="produto.id">
<td>{{produto.nome}}</td>
<td>{{produto.quantidade}}</td>
<td>{{produto.valor}}</td>
<td>
<button class="waves-effect btn-small blue darken-1">
<i class="material-icons">create</i>
</button>
<button class="waves-effect btn-small red darken-1">
<i class="material-icons">delete_sweep</i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import Produto from "./services/produtos";
export default {
data() {
return {
produto: {
nome: "",
quantidade: "",
valor: ""
},
produtos: []
};
},
mounted() {
Produto.listar().then(resposta => {
console.log(resposta.data);
this.produtos = resposta.data;
});
}
};
</script>
<style>
</style>
in your produto.js file. salvar function, change to this:
salvar:() => {
return http.post('produto')
}
So you defined a produto, but never used in the function, that's why your eslint reports this error.
This is and extension of Hank's answer. Since you say its explicitly mentioned in the video to put produto as a parameter, try removing the inverted commas in the http post call:
salvar:(produto) => {
return http.post(produto)
}

How to pass a component to render in props in Vue Js?

I have a situation where i need to render data cell synamically
where tableProps contain all columns and dataProps.
tableProps: {
cols: [{
cellProps: {
class: "as"
},
cellRenderer: ((data) => {
return <a onlick = {
this.onDataClick
}
class = "btn btn-link" > {
data.name
} < /a>
}).bind(this),
dataKey: "name",
dataType: String,
label: "Name",
sortable: true
}
],
enableSelect: true,
onPageChange: this.onPageChange,
onSelect: (selectedRow) => console.log("selectedRow", selectedRow),
onSelectAll: (data) => console.log("slectAllClick", data),
page: 0,
rowProps: {
onClick: (event, rowData) => {
this.onClick(rowData);
}
},
rowsPerPage: 5,
title: "Nutrition"
}
There is a cell renderer where data can be passed to render custom data like buttons anchor etc..
the solution has been found, instead of sending a function, scoped slots can be used to render dynamic contents for each cell. Thank you for showing interest.
**Table.Vue(child, generic-table)**
<table class="table table-bordered">
<thead>
<tr>
<th v-for="col in options.cols" :key="col.id">
<template v-if="col.colRenderer">
{{col.colRenderer(col)}}
</template>
<template v-else>
{{col.label}}
</template>
</th>
</tr>
</thead>
<tbody>
<tr v-for="datum in data" :key="datum.id" #click="(e)=> options.rowProps.onClick ? options.rowProps.onClick(e, datum): ''">
<td v-for="col in options.cols" :key="col.id" #click="()=> col.onClick ? col.onClick(datum[col.dataKey]): ''">
<template v-if="col.cellSlot">
<slot :name="col.cellSlot.name" :data="datum[col.dataKey]"/>
</template>
<template v-else>
{{datum[col.dataKey]}}
</template>
</td>
</tr>
</tbody>
</table>
**Calling component(Parent, with Custom Data cells)**
<v-table
:name="carePlanName"
:options="tableProps"
:total-count="totalCount"
:data="users" >
<div
slot=""
slot-scope="slotProps">
<!-- Define a custom template for CellData Data -->
<!-- `slotProps` to customize each todo. -->
<span v-if="slotProps">✓
<button>{{ slotProps.name }}</button>
</span>
</div>
</v-table>

Vuejs2- Avoid repetition of select field options using vee-validate

Iam using vee-validate plugin for validation. In my form, there is a select field in the table. Rows will be added dynamically in the table. I don't want to select the same select(Description column) option again and again Image. Hence I want to throw an error like "Selected description already exists in a table" this using vee-validate. Kindly help me to solve this.
Here is my code:
<template>
<div>
<b-card>
<div class="panel-body" id="app">
<table class="table table-hover">
<thead>
<tr>
<th style="width: 20px;">No.</th>
<th style="width: 330px;">Description</th>
<th style="width: 130px;" class="text-right">Charges</th>
<th style="width: 130px;">Total</th>
<th style="width: 130px;"></th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in rows" :key="row.qty">
<td>
{{ index +1 }}
</td>
<td>
<select class="form-control" v-model="row.billChgDesc" v-validate="'required|check'" :name="'billChgDesc' + index" data-vv-as="Description" #change="checkRepetation">
<option v-for="option in billChgDescOpt" v-bind:value="option.value"
:key="option.value"> {{ option.text }}
</option>
</select>
<span v-show=" errors.has('billChgDesc' + index)" class="is-danger">{{ errors.first('billChgDesc' + index) }}</span>
</td>
<td>
<input class="form-control text-right" type="text" v-model="row.charges" data-type="currency" v-validate="'required'" :name="'charges' + index" data-vv-as="Charges" >
<span v-show=" errors.has('charges' + index)" class="is-danger">{{ errors.first('charges' + index) }}</span>
<td>
<input class="form-control text-right" :value="row.qty * row.charges" number readonly />
<input type="hidden" :value="row.qty * row.charges * row.tax / 100" number/>
</td>
<td>
<button class="btn btn-primary btn-sm" #click="addRow(index)"><i class="fa fa-plus"></i></button>
<button class="btn btn-danger btn-sm" #click="removeRow(index)"><i class="fa fa-minus"></i></button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3" class="text-right">TOTAL</td>
<td colspan="1" class="text-right"><input class="form-control text-right" v-model="delivery" number/></td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</b-card>
</div>
</template>
<script>
import Vue from 'vue'
import accounting from 'accounting'
export default {
data: function () {
return {
billChgDescOpt: [
{ value: '', text: 'Select' },
{ value: 'M', text: 'Maintenance Fee'},
{ value: 'W', text: 'Water Charges'},
{ value: 'P', text: 'Penalty Fee'},
],
rows: [
{qty: 5, billChgDesc: '', charges: 55.20, tax: 10},
{qty: 19, billChgDesc: '', charges: 1255.20, tax: 20},
],
grandtotal: 0,
delivery: 40,
selectArr:[]
}
},
methods: {
addRow: function (index) {
try {
this.rows.splice(index + 1, 0, {});
} catch(e)
{
console.log(e);
}
},
removeRow: function (index) {
this.rows.splice(index, 1);
},
checkRepetation:function(){
this.$validator.extend('check', {
getMessage: field => '* Slected ' + field + ' already exists',
validate: function(value){
selectArr.push(value);
}
})
}
}
}
</script>
<style lang="scss" scoped>
.is-danger{
color: RED;
}
</style>
Thanks in advance.
You're on the right track, but a couple changes need to be made. When you call this.$validator.extend, that only needs to be done once - when your component is created. It attaches the check method to the validator, so then every time you have the attribute v-validate="'required|check'" in your HTML, it will run that check method.
In your check validator, you need to answer the question "is this value already selected". The answer is to go through the this.rows and see if any of them have the same billChgDesc property. Because this is in Vue, by the time the validator gets run, the row in question already does have that value, so you want to check if MORE than one row have that value. So, something like this:
mounted() {
var self = this;
this.$validator.extend('check', {
getMessage: field => '* Selected ' + field + ' already exists',
validate: function(value){
return (self.rows.filter(function(v){
return v.billChgDesc == value;
}).length <= 1);
}
});
}
This validator returns true if only one item has the given value. I'm using the built-in filter method of Array (see docs).
You can see an example of this all working here: https://jsfiddle.net/ryleyb/f9q50wx4/1/

Vue access iteration item inside method from template

Learning Vue and stuck.
I am trying to access user in each of the methods to confirm true/false values for each isHuman and isPlayerTurn functions. How do I access the user in the loop instance inside each method?
I have the following table row in a template:
<template>
<div class="col-xs-12">
<h5>Enemies online</h5>
<span id="no-online-players" class="player-label pull-right">{{ usersCount }}</span>
<table id="new-game-opponents" class="new-game-opponents">
<tbody>
<tr v-for="(user, index) in users" :key="index" :class="[isPlayerTurn() ? playerTurnClass : '']">
<td class="player-status text-right">
<div v-if="isPlayerTurn">
<span :id="['player_turn-' + user.owner_id]" class="stage-label pull-right">{{ progress }}</span>
</div>
<div v-else>
<i class="fa fa-clock-o" aria-hidden="true" style="margin-right:5px;"></i>
</div>
</td>
<td class="player-status text-right">
<div v-if="isHuman">
<i class="fa fa-desktop" aria-hidden="true"></i>
</div>
<div v-else>
<i class="fa fa-user" aria-hidden="true" style="margin-right:2px;"></i>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: ['users', 'usersCount'],
data: function () {
return {
playerTurnClass: 'next-player-turn',
myPlayer: my_player,
progress: game.progress.status.turn_status.current_stage
}
},
methods: {
isPlayerTurn: function(user, index) {
return this.myPlayer.id === this.users[index]['id'];
},
isHuman: function(user, index) {
return this.users[index]['owner_id'] !== 'ai';
}
}
};
</script>
I am trying to access user in each of the methods to confirm true/false values for each isHuman and isPlayerTurn functions.
How do I access the user in the loop instance inside each method? Or should I be doing this a different way?
Additionally, the progress property is not rendered. But one step at a time!
First of all, try
<div v-if="isPlayerTurn(user, index)">...</div>
and
<div v-if="isHuman(user, index)">...</div>
I noticed you don't really use user in both isPlayerTurn and isHuman methods, so I suggest leaving user out.
And regarding progress, I don't know where game is from, but I'm guessing the value in game.progress.status.turn_status.current_stage is dynamic, so I suggest you first try changing progress to a computed property:
computed: {
progress() {
return game.progress.status.turn_status.current_stage
}
}