VueJs autofocus on new row [duplicate] - javascript

This question already has answers here:
vue.js put focus on input
(5 answers)
Closed 2 years ago.
I have dynamic rows where it adds new row by clicking on button OR scan input success, now the issue is that I can't get focus on new row.
Demo
Code
To avoid confusion I've commented all lines in code.
Template
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<td><strong>Serial Number</strong></td>
<td width="50"></td>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in form.barcode_serial_number" :key="index">
<td>
<el-input ref="barcode" v-model="row.barcode_serial_number"></el-input>
</td>
<td>
<el-link v-on:click="removeElement(index);" style="cursor: pointer">Remove</el-link>
</td>
</tr>
</tbody>
</table>
<div>
<button type="button" class="button btn-primary" #click="addRow">Add row</button>
</div>
Script
data() {
return {
form: {
barcode_serial_number: [], //get data of all rows
},
}
},
created() {
//scanner
const eventBus = this.$barcodeScanner.init(this.onBarcodeScanned, { eventBus: true })
if (eventBus) {
eventBus.$on('start', () => {
this.loading = true;
console.log('start')
})
eventBus.$on('finish', () => {
this.loading = false;
console.log('finished')
// add new row when scan succeed
this.$nextTick(function () {
this.form.barcode_serial_number.push({
barcode_serial_number: ''
});
})
})
}
},
methods: {
// add autofocus to new row
focusInput() {
this.$refs.barcode.focus();
},
// add new row by clicking button
addRow: function() {
var barcodes = document.createElement('tr');
this.form.barcode_serial_number.push({
barcode_serial_number: ''
});
},
// remove row by clicking button
removeElement: function(index) {
this.form.barcode_serial_number.splice(index, 1);
},
}
Question
How do I set autofocus on newly added rows?

At the moment the new serial_number is inserted the DOM is not updated so we cant focus it.
We need to use nextTick to run a function when the DOM is updated.
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: '#app',
data: {
form: {
barcode_serial_number: []
}
},
methods: {
addRow() {
this.form.barcode_serial_number.push({
barcode_serial_number: ''
});
this.$nextTick(() => {
const nbBarcodes = this.$refs.barcode.length;
this.$refs.barcode[nbBarcodes - 1].focus();
});
},
removeElement(index) {
this.form.barcode_serial_number.splice(index, 1);
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<thead>
<tr>
<td><strong>Serial Number</strong></td>
<td width="50"></td>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in form.barcode_serial_number" :key="index">
<td>
<input ref="barcode" v-model="row.barcode_serial_number"></input>
</td>
<td>
<button v-on:click="removeElement(index);">Remove</button>
</td>
</tr>
</tbody>
</table>
<div>
<button #click="addRow">Add row</button>
</div>
</div>

Related

how to create/add a new table row with javascript alone

What Im trying to do:
Use peopleDropdown to add the new person to the person dropdown within createPerson
Use peopleTable to add a new table row within createPerson
main.js:
class Dropdown {
constructor(idSelector) {
this.idSelector = idSelector;}
getCurrentSelection() {
return $(this.idSelector).val();}
appendToDropdown(label, value) {
$(this.idSelector).append(`<option value=${value}>${label}</option>`);}
}
class Table {
constructor(idSelector) {
this.selector = idSelector;
}
appendRow(data) {
let tableRows = `
<td class="name-col"></td>
<td class="balance-col"></td>
<td class="consumed-col"></td>
`;
$(this.selector).append(`<tr id="">${tableRows}</tr>`);
}
modifyRow(/*define inputs*/) {}
}
const peopleDropdown = new Dropdown('#people-dropdown');
const peopleTable = new Table(`#person-table tbody`);
const allPeople = [];
const createPerson = () => {
let name = getNameInput();
allPeople.push(name);
//peopleDropDown code
//peopleTable code
}
I'm stuck on how to add the tables since my regular way of doing this would be using react as the framework. (which is not a option here)
Html:
<div id="creator-row">
<input id="name-input" placeholder="Name" />
<button onclick="createPerson()">Create Person</button>
</div>
<div id="consume-row">
<label for="person-list">Choose a person:</label>
<select name="person-list" id="people-dropdown"></select>
</div>
<table id="person-table">
<thead>
<tr class="header-row">
<th class="name-col">Name</th>
</tr>
</thead>
<tbody></tbody>
</table>
This snippet only answers the question of how to add the rows to the table
const table = document.getElementById("person-table");
const tbody = table.querySelector("tbody");
const tr = document.getElementById("tr");
// some people
const people = [{
"name": "one",
"balance": 1,
"consumed": 1
},
{
"name": "two",
"balance": 2,
"consumed": 2
},
{
"name": "three",
"balance": 3,
"consumed": 3
},
];
// loop through the people and add them to the table
people.forEach(p => {
const newRow = tr.content.cloneNode(true);
const cells = newRow.querySelectorAll("td");
cells[0].textContent = p.name;
cells[1].textContent = p.balance;
cells[2].textContent = p.consumed;
tbody.appendChild(newRow);
});
td {
border: 1px solid #000;
}
<table id="person-table">
<thead>
<tr class="header-row">
<th class="name-col">Name</th>
<th class="balance-col">Balance</th>
<th class="consumed-col">Consumed</th>
</tr>
</thead>
<tbody></tbody>
</table>
<!-- a template of the row -->
<template id="tr">
<tr>
<td class="name-col"></td>
<td class="balance-col"></td>
<td class="consumed-col"></td>
</tr>
</template>

How to do pagination in Vue.js table?

I have a web app, frontend using Vue.js, backend using Django.
How could I do pagination in my Vue.js table?
I have tried jQuery DataTable but it's pagination loads very slow, which could not meet user's requirements.
<div id="app">
<form ref="form" id="myform" method="post" action="/tag_course/">
<table id="myTable">
<thead>
<tr>
<th>Course Material Title</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in filteredRows" :key="`isbn-${index}`">
<td v-html="highlightMatches(row.title)">{{ row.title }}</td>
</tbody>
</table>
</form>
</div>
<script>
var book_rows = [{title: query_results_book[0].fields.title}]
const app = new Vue({
el: '#app',
data:() => ({
filter: '',
rows: book_rows
}),
computed: {
filteredRows() {
return this.rows.filter(row => {
const author =
String(row.author).toString().toLowerCase();
const title = String(row.title).toLowerCase();
const searchTerm = this.filter.toLowerCase();
return title.includes(searchTerm) ||
author.includes(searchTerm);
});
}
},
});
</script>

How to filter data with checkbox in Vuejs with API?

I would like to filter data in table using checkbox and outoput data will be shown based on checked/unchecked, for example when i'm checked "Show All" will ouput all data, and when i'm unchecked then output only will show some data. but when i'm trying to do this, the result nothing changed when i'm checked
here for vue html:
<div class="col-md-8">
<input type="checkbox" id="checkboxOrder" v-model="checkedValue" value="Onloading Complete" >
<label for="checkboxOrder">Show All</label>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>code</th>
<th>price</th>
<th>status</th>
<th>transporter</th>
<th>driver</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in showOrderDetail" :key="index">
<td >{{Number(index)+1}}</td>
<td>{{item.code}}</td>
<td>{{formatNumber(item.invoice_price)}}</td>
<td :class="statusBackground(item)">
<template v-if="item.t_tour">
<span v-if="!_.isEmpty(item.t_tour.t_tour_detail)">
{{item.t_tour.t_tour_detail[0].status}}
</span>
<span v-else>Unproccess</span>
</template>
<span v-else>Unproccess</span>
</td>
<td class="bg-warning">{{item.m_transporter ? item.m_transporter.name : 'unproccess'}}</td>
<td>{{driver(item)}}</td>
<td><span class="btn btn-primary" #click="showModal(item.t_tour)"><i class="fas fa-search"></i></span></td>
</tr>
</tbody>
</table>
and my vue.js :
import axios from "axios";
import accounting from "accounting";
import ShowTourDetail from "~/pages/transaction/order/ShowTourDetail";
export default {
props: {
rowData: {
type: Object,
required: true
},
rowIndex: {
type: Number
}
},
data() {
return {
t_order_detail: {},
checkedValue:[]
};
},
mounted() {
this.fetchData();
},
computed:{
showOrderDetail(){
if(!this.checkedValue.length)
return this.t_order_detail
return this.t_order_detail.filter(o => this.checkedValue.includes(o.t_tour.t_tour_detail[0].status))
}
},
methods: {
async fetchData() {
this.t_order_detail = {
...(
await axios.get(`/api/order-details`, {
params: { t_order_id: this.rowData.id }
})
).data
};
}
};
You can apply change method like :
<input type="checkbox" :value="mainCat.merchantId" id="mainCat.merchantId" v-model="checkedCategories" #change="check($event)">
Methos like:
methods: {
check: function(e) {
if(e.target.checked){
console.log("load all data using service");
// service call here
}else{
console.log("load required data using service");
// service call here
}
}
}

How to use data or methods across different components

I have a HTML table in which in one component I have table head and other stuff and in other component I have tbody so in every row of tbody I am adding a delete row button which I want to delete but the data is in theadcomponent there is no parent-child relation here so how can I do this.
My code
Vue.component("form-row", {
template: "#row-template",
props: {
itemname: String,
quantity: Number,
sellingprice: Number,
amount: Number
},
methods: {
delete() {
alert("tedt")
}
},
computed: {
quantitySynced: {
get() {
return this.quantity;
},
set(v) {
this.$emit("update:quantity", +v);
}
},
sellingpriceSynced: {
get() {
return this.sellingprice;
},
set(v) {
this.$emit("update:sellingprice", +v);
}
},
amountSynced() {
this.$emit("update:amount", parseFloat(this.quantity) * parseFloat(this.sellingprice));
return this.amount
}
}
});
new Vue({
el: "#app",
data() {
return {
tableDatas: []
};
},
methods: {
btnOnClick(v) {
this.tableDatas.push({
itemname: "item",
quantity: 1,
sellingprice: 55,
amount: 55
});
}
},
computed: {
calculate() {
return (
this.tableDatas.reduce((total, {
amount
}) => total + amount, 0) || 0
);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button type="button" #click="btnOnClick">Add</button>
<table class="table table-striped table-hover table-bordered mainTable" id="Table">
<thead>
<tr>
<th class="itemName">Item Name</th>
<th>Quantity</th>
<th>Selling Price</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<form-row v-for="(row, key) in tableDatas" :key="key" v-bind.sync="row"></form-row>
</tbody>
</table>
<div>
<label>Total Row's Amount</label>
<input type="text" disabled :value="calculate">
</div>
</div>
<script type="text/x-template" id="row-template">
<tr>
<td>
<input class="form-control" readonly :value="itemname" />
</td>
<td>
<input class="form-control text-right" type="number" min="0" step="1" v-model="quantitySynced" />
</td>
<td>
<input class="form-control text-right" type="number" min="0" step=".5" v-model="sellingpriceSynced" />
</td>
<td>
<input readonly class="form-control text-right" type="number" min="0" step="1" :value="amountSynced" />
</td>
<td>
<button>Delete</button>
</td>
</tr>
</script>
Here I have two components In one component delete button is the I know how to delete the row in same component by using this:
delete(index) {
console.log("Removing", index);
this.tableDatas.splice(index, 1);
}
Vue Mixins will work for your problem.
Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.
Here is an example;
// define a mixin object
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
Use the Shared events to catch between parent to component
var sharedEvents = new Vue();---declare on top of the vue instance
//parent
new Vue({
el: "#app",
---code--
methods:
getData(){
//emit the data in parent like this
sharedEvents.$emit('forceInjectGridData', {id: "billing-grid", data: data});
}
});
And catch the data in component like below wherever you want:
methods:{
forceInjectGridData(v) {
if (this.id === v.id) {
this.gridData = v.data;
//do your coding here
}
},
} ,
mounted(){
sharedEvents.$on('forceInjectGridData', this.forceInjectGridData);
}

Add comma separated value to separate lines in VUE JS

Hi guys I have the following code where I look over a json file and add the data to a table.
I want the data from product.refrencing_category_ids to be output in on separate lines instead being in one line like this:
bc-men,bc-men-fashion,bc-men-underwear
I would like it to look like:
bc-men,
bc-men-fashion,
bc-men-underwear
How would i go about doing that? Would I need another for loop for the product.refrencing_category_ids?
My code look like this:
<template>
<div>
<h1>Category Assignment</h1>
<table class="table">
<tr class="table-header">
<th>ID</th>
<th>Name</th>
<th>Primary category</th>
<th>Refrencing categories</th>
<th>Add</th>
<tr>
<tr class="product" v-for="product in products">
<td class="product__item"><input required type="text" v-model="product.id"></td>
<td class="product__item"><input required type="text" name="fname" v-model="product.name"></td>
<td class="product__item">
<input required type="text" name="fname" v-model="product.primary_category_id">
</td>
<td class="product__item">
<input required type="text" name="fname" v-model="product.refrencing_category_ids">
</td>
<td class="product__item">
<button v-on:click="product.quantity += 1">
Add
</button>
</td>
</tr>
</table>
<h2>Total inventory: {{ totalProducts }}</h2>
</div>
</template>
<script>
export default {
name: 'ProductEnrichment',
data () {
return {
products: [],
productHeadline: 'Product Flow Tool'
}
},
computed: {
totalProducts () {
return this.products.reduce((sum, product) => {
return sum + product.quantity
}, 0)
}
},
created () {
fetch('https://www.fennefoss.dk/product-request.json')
//fetch('./sample.json')
.then(response => response.json())
.then(json => {
this.products = json.products
})
}
}
</script>
Yes to another loop with v-for. To make the list item reactive, you need to update the original data and not the computed one. Something like this:
new Vue({
el: '#app',
data() {
return {
product: {
refrencing_category_ids: 'bc-men,bc-men-fashion,bc-men-underwear'
}
}
},
methods: {
remove(idx) {
let items = this.product.refrencing_category_ids.split(',');
let removed = items.splice(idx, 1);
this.product.refrencing_category_ids = items.join(',');
}
},
computed: {
refCatIds() {
return this.product.refrencing_category_ids.split(',');
}
}
})
ul {
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="(id, index) in refCatIds" :key="index">
{{id}}
</li>
</ul>
</div>
Replace all of the commas with \n (newline character)
let string = "bc-men,bc-men-fashion,bc-men-underwear"
console.log(string.replace(/,/g, '\n'))

Categories

Resources