Edit object of an array using Vue.JS - javascript

I am developing my first app using Vuejs + Laravel and I am facing a problem that I couldn't solve until now!
I have an array of object and I need to edit a single of then without delete and add a new one! I have made a JS Bin to show what I need!
JS Bin
When you click in EDIT and start to typing your new value the original value edits as well but I need to change the original value only after the user hit the save button!
Anybody can help me?
PS: I will update my database and then show the new value on the table!
Is there anyway to duplicate my record as I do on the edit function without sync then?
JS
new Vue({
el: 'body',
data: {
cache: {},
record: {},
list: [
{ name: 'Google', id: 1 },
{ name: 'Facebook', id: 2 },
],
},
methods: {
doEdit: function (record) {
this.cache = record;
},
edit: function (record) {
this.record = _.cloneDeep(record);
this.cache = record;
}
}
});
HTML
<div class="container">
<form class="form-horizontal" #submit.prevent="doEdit(record)">
<div class="row">
<div class="col-md-12">
<label>Name</label>
<input type="text" class="form-control" v-el:record-name v-model="record.name">
</div>
<div class="col-xs-12" style="margin-top:15px">
<button type="submit" class="col-xs-12 btn btn-success">Save</button>
</div>
</div>
</form>
<hr>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="r in list">
<td class="text-center" style="width:90px"> {{ r.id }} </td>
<td> {{ r.name }} </td>
<td class="text-center" style="width:90px">
<span class="btn btn-warning btn-xs" #click="edit(r)"><i class="fa-fw fa fa-pencil"></i></span>
</td>
</tr>
</tbody>
</table>
</div>

You can replace the old object with the cloned-updated one.
doEdit: function (record) {
var index = _.indexOf(this.list, this.cache);
this.list.splice(index, 1, record);
}
https://jsbin.com/ruroqu/3/edit?html,js,output

If you want to save the value only after user submitted, you should not bind the record directly such as v-model="record.name".
And we can use Vue.set to change attributes of the original record.
Let's try: JS Bin

Related

Building a table that pulls data from MongoDB that filters in real time, and sorts alphabetically

As the title suggests, that is what im attempting to do, but are at a lost. My best attempt is the following:
This is the nodejs code that renders the HTML page and gets the user input from HTML
app.get('/search/species', (req,res) => {
diseaseModel.find({matched: current_matched}, function (err,disease){
res.render('species', {
diseaseList: disease,
});
});
})
app.post('/search/species', async(req,res) => {
var desc = req.body.desc;
await diseaseModel.updateMany({matched: current_matched, "$text":{"$search" : `\"${desc}\"`}}, {$inc: {matched: 1}});
current_matched ++;
res.redirect(302, '/search/species');
}
}
});
})
This is the HTML page that I uses to collect user input and return the filtered options:
<form action = "/search/species" method = "POST" id="submitMessage" class="field has-addons">
<input class="form-control input is-primary" name = "desc" id = "desc" type="text" style="width: 100%;" placeholder="Enter a Description" required/>
<button type="submit" class="button is-primary" id="send">Send</button>
</form>
</div>
</div>
</section>
<table class = "content-table" align="center" style="margin: 0px auto;">
<thead>
<tr>
<th>Name</th>
<th>Species</th>
<th>Vector</th>
<th>Agent</th>
</tr>
</thead>
<tbody>
<%diseaseList.forEach(disease =>{%>
<tr data-href= 'http://localhost:8080/info?id=<%=disease.id%>'>
<th><%=disease.diseaseName%></th>
<th><%=disease.species%></th>
<th><%=disease.vector%></th>
<th><%=disease.agent%></th>
</tr>
<% })%>
</tbody>
</table>
</div>
</section>
<script>
$(document).ready(function() {
$(document.body).on("click", "tr[data-href]", function() {
window.location.href = this.dataset.href;
})
});
But this doesn't refresh in real time, as in when i type a character, it doesn't start filtering. Would I be able to do this via AJAX? Also how would I list MongoDB data out in the table in alphabetical order?

Vee validate v3 ValidationObserver not working with dynamic validation provider added using v-for

I am using Vee Validate v3 for validating dynamic input generated using V-FOR, which is added or removed input elements based on user actions.
My issue was only the last input gets validated other inputs not getting validated. In the documentation, they had mentioned this issue while using V-IF & V-FOR
documentation link
They told to use VueJS keep-alive component. but not working with V-FOR.
<validation-observer ref="observer" v-slot="{ handleSubmit }">
<form method="POST" action="{{ route('app.store') }}" #submit.prevent="handleSubmit(onSubmit)" class="form" enctype="multipart/form-data">
<table class="table">
<thead>
<tr>
<th>SI No</th>
<th>input 1</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in items" :key="item.id">
<td>#{{ index + 1 }}</td>
<td>
<keep-alive>
<validation-provider rules="required" v-slot="{ errors }" name="attribute">
<div class="form-group">
<input :name="'attribute' + item.id" class="form-control" v-model="item.attribute">
<span class="error" role="alert">
#{{ errors[0] }}
</span>
</div>
</validation-provider>
</keep-alive>
</td>
<td>
<button type="button" class="btn btn-md btn-danger mt-4" #click="remove(index)">
<span class="ion-trash-a"></span>
</button>
</td>
</tr>
</tbody>
</table>
<x-form-submit>Save</x-form-submit>
</form>
My js code
<script type="application/javascript">
Vue.component('dynamic-form-wrapper', {
template: '#dynamic-form-template',
data() {
return {
items: [
{
id: 1,
attribute: null,
},
{
id: 2,
attribute: null,
}
],
id: 3
}
},
methods: {
async onSubmit() {
const valid = await this.$refs.observer.validate();
if (valid) {
document.getElementById("category-form").submit();
}
},
add() {
this.items.push({
id: this.id,
attribute: null,
});
this.id ++;
},
remove(index) {
if (this.items.length != 1) {
this.items.splice(index, 1);
}
}
}
})
</script>
Thanks in advance
Each ValdationProvider needs a unique id. set :vid for each validation providers
<keep-alive>
<validation-provider :vid="'attribute' + item.id" rules="required"
v-slot="{ errors }" name="attribute">
<x-v-form-input type="text" v-model="item.attribute" field="attribute">
</x-v-form-input>
</validation-provider>
</keep-alive>
Refer API docs for vid here: https://vee-validate.logaretm.com/v3/api/validation-provider.html#props

Hiding and un-hiding table div based off of data being returned

I have a table that I want to be hidden there is no data to be displayed.
I have a controller action that returns data to display for the table. If data is returned, I want the table to be show, otherwise I want it hidden. I have tried several approaches to this and it seems like my fix is working (for a few seconds) but then once the controller returns the model, the table becomes hidden again. I am doing something wrong. How can I fix this? Below is my code:
HTML:
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "submitForm"}))
{
<div class="row">
<div>
#Html.DropDownList("CasinoID", Model.TerminalReceiptPostData.CasinoIdDDL, "Select Casino", new { id = "cIdSearch", #class = "custom-class-for-dropdown card" })
</div>
<div>
<input id="datepicker" class="datepicker-base card" name="Date" placeholder="MM/DD/YYY" type="text"/>
</div>
<div>
<button type="submit" class="btn btn-sm btn-primary" id="search"> Search Transactions</button>
</div>
</div>
}
<hr />
<div class="row" id="ReceiptsMainDiv">
<div class="col-md-12" style="overflow-y:scroll">
<table class="table table-striped table-hover table-bordered" id="terminalReceipts">
<thead>
<tr>
<th>Terminal ID</th>
<th>Local Transaction Time</th>
<th>Amount</th>
<th>Receipt</th>
<td class="hidden"></td>
</tr>
</thead>
<tbody>
#foreach (var item in Model.TransactionsTests)
{
<tr id="#String.Concat("rowIndex", Model.TransactionsTests.IndexOf(item))">
<td>#item.TerminalID</td>
<td>#item.TransactionTime</td>
<td>#item.Amount</td>
#*<td>#Html.ActionLink("View Receipt", "ViewReceipt", new { id = item.Id }, new { #class = "btn btn-primary btn-sm" }) <br /></td>*#
<td class="transactionID hidden">#item.Id</td>
<td>
#if (item.ReceiptData == null)
{
<button class="btn btn-sm btn-primary viewReceipt" disabled>View Receipt</button>
}
else
{
<button class="btn btn-sm btn-primary viewReceipt" data-rowindex="#String.Concat("rowIndex", Model.TransactionsTests.IndexOf(item))">View Receipt</button>
}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
Controller action:
[HttpPost]
public ActionResult Index(string CasinoID, DateTime Date)
{
//var id = Int32.Parse(Request.Form["CasinoID"].ToString());
var Cid = Request.Form["CasinoID"];
Cid = GetNumbers(Cid);
var id = Int32.Parse(Cid);
var model = TRBL.GetTransactionTestsData(id, Date);
model.TerminalReceiptPostData = TRBL.GetCasinosDDL();
return View(model);
}
and finally my JS function:
window.onload = function () {
$("#ReceiptsMainDiv").toggle();
var rowCount = $("#rowindex").length;
console.log(rowCount);
if (rowCount > 0) {
$("#ReceiptsMainDiv").toggle();
}
};
As you can see, the Form at the top contains the button, and the block below is the table that needs to be toggled.
Let me know if there is anything else you guys would need.
When you have results to show, <tr id="#String.Concat("rowIndex", Model.TransactionsTests.IndexOf(item))"> will not produce ids of "rowIndex" (unlike what you might be expecting). Instead, you will have "rowIndex0", "rowIndex1", etc. Therefore, after rowCount will be zero, and your will not toggle.

How to delete a particular row from table by clicking button Angular 2

I am trying to delete a particular row by clicking button from that row which is in for loop,but its deleting all the rows of that table.
Here is my Html code:
<table id="mytable" class="table table-bordred table-striped">
<tbody id="del">
<tr *ngFor="let cart of modalData">
<td>
<div style="display:inline-flex;">
<div style="margin-left:10px;">
<p class="font_weight" style="font-size:13px;">{{cart.ExamName}}</p>
<p>{{cart.Categoryname}}|{{cart.CompanyName}}</p>
</div>
</div>
</td>
<td>
<div style="margin-top: 32px;">
<p class="font_weight" style="font-size:13px;"></p> <span class="font_weight" style="font-size: 13px;"> {{cart.Amount| currency :'USD':'true'}} </span> </div>
</td>
<td>
<div style="margin-top: 19px;">
<button class="button_transparent" (click)="Delete(cart)"> delete </button>
</div>
</td>
</tr>
<tr> </tr>
</tbody>
</table>
Here is my Component:
public loadData() {
let transaction = new TransactionalInformation();
this.myCartService.GetExamOrderForCart()
.subscribe(response => this.getDataOnSuccess(response),
response => this.getDataOnError(response));
}
getDataOnSuccess(response) {
this.modalData = response.Items;
}
This is my delete method:
public Delete(response) {
this.myCartService.updateExamOrder(response)
.subscribe(response => this.getDataOnSuccessForDelete(response),
response => this.getDataOnErrorForDelete(response));
}
Please help me to do, How to delete only one row from table?
You can add index in *ngFor :
<tr *ngFor="let cart of modalData;let i = index">
Then, pass the index in the method:
<button class="button_transparent" (click)="delete(i)"> delete </button>
And finally:
delete(i){
this.modalData.splice(i,1);
}
you can do this:
<button class="button_transparent" (click)="delete(cart)"> delete </button>
then
delete(item){
this. modalData = this. modalData.filter(item => item.id !== id);
this.modalData.push();}
here you are creating a new list without the element that you want to delete.

Add object to an KnockoutJS after input validation

I want to validate the user input before adding the object to an observable. For example if I have two fields, say Quantity and Price, before adding the object to the observable I want to validate the user input.
How can I achieve this behavioral?
The code that I have so far:
self.productPriceAdd = function () {
var newPrice = {
Quantity: self.newProductPriceEntry.Quantity(),
Price: self.newProductPriceEntry.Price(),
ProductBarcode: self.productPrices().Barcode
}
self.productPrices().ProductSalePrices().push(newPrice);
self.productPrices().ProductSalePrices(self.productPrices().ProductSalePrices());
self.newProductPriceEntry.Quantity(null);
self.newProductPriceEntry.Price(null);
}
The user interface looks somethig like this:
So after the user clicks the Add button, two error messages should be displayed, one for each empty field.
My HTML code:
<!-- ko if: productPrices() -->
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title"><b data-bind="text: productPrices().Name"></b></h2>
</div>
<table class="table">
<tr>
<th>
#Html.DisplayName("Quantity")
</th>
<th>
#Html.DisplayName("Price")
</th>
<th></th>
</tr>
<tbody data-bind="foreach: productPrices().ProductSalePrices()">
<tr>
<td>
<b data-bind="text: Quantity"></b>
</td>
<td>
<b data-bind="text: Price"></b>
</td>
<td>
Remove
</td>
</tr>
</tbody>
<tbody data-bind="with: newProductPriceEntry">
<tr>
<td>
<input type="number" class="form-control" data-bind="value: Quantity " placeholder="Quantity">
</td>
<td>
<input type="number" step="0.01" class="form-control" data-bind="value: Price " placeholder="Price">
</td>
<td>
Add
</td>
</tr>
</tbody>
</table>
</div>
Save
Have a look at Knockout-Validation. It is a Knockout plugin that simplifies the validation process.
https://github.com/Knockout-Contrib/Knockout-Validation
So, the solution I found is to check for false values for Quantity and Price field. Are evaluated to false the following types: false, "", undefined and null.
So, the full working code:
self.productPrices = ko.observable();
self.newProductPriceEntry = {
Quantity: ko.observable("").extend({ required: true }),
Price: ko.observable("").extend({ required: true })
}
self.productPriceAdd = function () {
var newPrice = {
Quantity: self.newProductPriceEntry.Quantity(),
Price: self.newProductPriceEntry.Price(),
ProductBarcode: self.productPrices().Barcode
}
if (newPrice.Price && newPrice.Quantity) {
self.productPrices().ProductSalePrices().push(newPrice);
self.productPrices().ProductSalePrices(self.productPrices().ProductSalePrices());
}
self.newProductPriceEntry.Quantity(null);
self.newProductPriceEntry.Price(null);
}
So what I am doing is to push the object into the observable only if the condition is true. Then set the observables to null to clear the fields.
For the number part validation I used the number HTML5 attribute.

Categories

Resources