How to get index of changed array under $watch in vuejs - vue.js

I am using an array of objects
({"code":"id1","color":"red","description":"eg1"})
where each object contains input fields.User can dynamically add and remove those objects.
Now I want that when he enters code rest of the field should be filled automatically.
For that I have developed an algorithm which will take the code and will give me the color and description but for that I need the POSITION of the object which is changed so that I can update the array on that index itself.
Below is my share of code:
<div v-for="(x,i) in fabric_arr">
<!--<pre>{{x}}</pre>-->
<div class="row">
<div class="col-md-4">
<span>
<input type=”text” list="idOfDatalist" class="form-control border-input" placeholder="Fabric Code" v-model="x._id">
<datalist id="idOfDatalist">
<option v-for="y in all_fabrics">{{y._id}}</option>
</datalist>
</span>
</div>
<div class="col-md-4">
<span>
<input type=”text” class="form-control border-input" placeholder="Fabric Color" v-model="x.color"></span>
</div>
<div class="col-md-4">
<span>
<input type=”text” class="form-control border-input" placeholder="Fabric Description" v-model="x.description"></span>
</div>
</div>
</div>
And my controller:
watch: {
fabric_arr: {
handler : function (val) {
console.log("val");
console.log(val);
//val.color="red always";
this.fabric_arr[0].color="fghjkl"
},
deep: true
}
}

For all those who are looking for the answer,use v-bind:change() to trigger the changes and manipulate index there.
Below is the code:
<input type=”text” list="idOfDatalist" class="form-control border-input" placeholder="Fabric Code" v-model="x._id" v-bind:change="inpChangedForCode(x)">
<datalist id="idOfDatalist">
<option v-for="y in all_fabrics">{{y._id}}</option>
</datalist>

Related

drop down select field stays null Livewire

I'm trying out Livewire for the first time. The drop-down is populated from the database. Similar codes works for text fields, but fails with drop-down select fields.
Edit: The form is inside a bootstrap modal
Code is as below: The livewire component (leads-form.blade)
<div class="modal-content">
<form wire:submit.prevent="submit">
#csrf
<div class="input-field col s12">
<label for="role">Client</label>
<select class="error validate" wire:ignore id="client_id" wire:model="client_id">
<option disabled value=" ">Client</option>
#foreach($clients as $client)
<option value="{{$client->id}}"> {{$client->clientname}}</option>
#endforeach
</select>
</div>
<div class="input-field col m12 s12">
<input id="contactperson" type="text" name="contactperson" wire:model="contactperson" />
#error('contactperson') <span class="error"><small>{{ $message }}</small></span> #enderror
<label for="contactperson">Contact Person</label>
</div>
<div class="row">
<div class="row">
<div class="input-field col s12">
<button class="btn cyan waves-effect waves-light right" type="submit">Add
<i class="material-icons right">send</i>
</button>
</div>
</div>
</div>
</form>
</div>
Next Livewire leads class is as a below:
class LeadsForm extends Component
{
public $contactperson;
public $client_id;
public function submit()
{
Lead::create([
'client_id' => $this->client_id,
'contactperson' => $this->contactperson,
]);
Alert::toast('Client created successfully', 'success');
return $this->redirectRoute('leads.index');
}
public function render()
{
$clients = Client::all();
return view('livewire.leads-form',[
'clients'=>$clients,
]);
}
}
I'm using the laravel debugbar, and it shows the array client_id field as null.
Remove the wire:ignore in the select element, that avoid produce any Livewire event that can be wrapped to backend
<select class="error validate" wire:ignore id="client_id" wire:model="client_id">
<option disabled value=" ">Client</option>
#foreach($clients as $client)
<option value="{{$client->id}}"> {{$client->clientname}}</option>
#endforeach
</select>

VueJS - v-model in for-loop

I'm trying to build something like the questions in OkayCupid, but all the questions - which are different forms - are located on the same component.
I use an object of questions and 3 possible answers for each question, and I use v-for to loop through the object and create cards with a question, 3 answers with radios, and a submit button.
The problem is that I want to get not only the answer the user chooses, but also the question it belongs to.
Here is my form in the template:
<div class="container">
<div class="row">
<div
class="col-lg-3 col-md-4 col-6"
v-for="(question,index) in questionCollection"
:key="index"
>
<form class="form">
<div class="img-fluid img-thumbnail shadow-lg p-3 mb-5 bg-white rounded">
<!-- <input type="text" :value="question.question" v-model="q" /> -->
<h3 class="d-block mb-4 h-100" alt data-holder-rendered="true">{{ question.question }}</h3>
<div class="card-body container">
<div class="card-text form-check">
<input
class="form-check-input"
type="radio"
name="gridRadios"
id="a1"
:value="question.answer1"
v-model="answer"
/>
<h4 class="font-weight-light" for="a1">{{ question.answer1 }}</h4>
</div>
<div class="card-text form-check">
<input
class="form-check-input"
type="radio"
name="gridRadios"
id="a2"
:value="question.answer2"
v-model="answer"
/>
<h4 class="font-weight-light" for="a2">{{ question.answer2 }}</h4>
</div>
<div class="card-text form-check">
<input
class="form-check-input"
type="radio"
name="gridRadios"
id="a3"
:value="question.answer3"
v-model="answer"
/>
<h4 class="font-weight-light" for="a3">{{ question.answer3 }}</h4>
</div>
</div>
<div class="card-text container">
<small class="text-muted">{{ question.user }}</small>
<button
href="#"
class="btn btn-primary my-3 mx-10 btn float-right shadow-sm rounded"
#click.prevent="answerQuestion"
>Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
And the script:
export default {
name: "questions",
data() {
return {
q: null,
answer: null
};
},
}
As you can see, at the beginning of the form, I tried to get the question element using v-model in a "fake" input, but it gives me an error that it's conflicted with the v-bind of the value (the question) I want to grab. Of course, I can't use v-model on the headline itself because Vue allows to use it only on inputs.
I've tried to change the v-model into v-model="questionCollection[index].question, but then I have no idea how to get it in the script and, let's say, log it to the console with the corresponding answer.
One way to handle this is to submit the question and answer together in the Save button's click-handler. That is, change answerQuestion() to receive question (the iterator variable in v-for) and answer, and update the Save button's click handler in the template to pass those two variables:
// template
<div v-for="(question, index) in questionCollection">
...
<button #click.prevent="answerQuestion(question, answer)">Save</button>
</div>
// script
answerQuestion(question, answer) {
console.log({ question, answer })
}
demo

How can I save multiple value in v-model on vue.js 2?

My vue component like this :
<template>
<div class="panel panel-default">
<a #click="deleteAll" href="javascript:" class="btn btn-danger pull-right">
<span class="fa fa-trash"></span> Delete All
</a>
...
<tr v-for="item in list">
<td>
<div class="checkbox">
<label>
<input type="checkbox" :value="item.id" v-model="checkedData">
</label>
</div>
</td>
...
</tr>
...
</div>
</template>
<script>
export default {
data() {
return {
checkedData: []
}
},
methods: {
deleteAll() {
this.$http.post(window.BaseUrl+'/message/deleteAll', {ids: this.checkedData})
}
}
}
</script>
If I check the some checkbox and click delete all button, it will send value item.id by ajax
I want to send another value too. I have value item.seller_id and item.buyer_id
I try like this :
<input type="checkbox" :value="item._id+'#'+item.seller_id+'#'+item.buyer_id" v-model="checkedData">
So I use separator # to separate the value. Seems it works
Whether it is the best solution? Or is there another better solution?
Hi please look at this https://jsfiddle.net/p8zhrg6g/29/ .
<div v-for="item in list">
<input type="checkbox" :id="item.id" :value="item.value" v-model="checkedNames">
<label :for="item.id">{{item.value}}</label>
This is how I would have done it, hope this helps?
Just put value in array in :value..
<div v-for="item in list">
<input type="checkbox" :id="item.id" :value="[item.name, item.value]" v-model="checkedNames">
<label :for="item.id">{{item.value}}</label>
When you want call the value in another element, you can call value based on their value index like {{item[0]}} will display item.name and {{item[1]}} will display value.value

Using vue js with selectpicker

I'm using Vue.js to add multiple rows, each row contain two datetimepicker inputs and a bootstrap-select.
My problem is when I fill the inputs and click to add a new row the previous ones clear out, the reason is each time I add a new row I'm using setTimeout to referesh the selectpicker and the datetimepicker.
So I want to know if there is a way to trigger the last added element them without refreshing the previous ones.
Here is my code :
HTML
<div class="cols" id="app">
<ul style="list-style-type: none;">
<li>
<button style="float: right;margin-right: 20px;margin-top: 5px;" type="button" class="btn btn-success btn-xs" v-on:click="addRow()">
<i class="fa fa-plus"></i> Ajouter
</button>
</li>
<li v-for="(row, id) in rows">
<div class="form-inline cp-out" style="padding-bottom: 9px;border-radius:4px;background-color:white;margin-left:-20px;display:inline-block;width:100%;margin-top:10px;">
<div class="col-md-3">
<label :for="['time_start'+id]" class="control-label">start time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_start'+id]" data-link-format="hh:ii">
<input v-model="row.startTime" :name="'rows['+id+'][startTime]'" class="form-control" :id="['startTime' + id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-3">
<label :for="['time_end'+id]" class="control-label" style="margin-left:7px;">end time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_end'+id]" data-link-format="hh:ii">
<input v-model="row.endTime" :name="'rows['+id+'][endTime]'" class="form-control" :id="['endTime'+id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group select_group" style="margin-left:5px;">
<label :for="['status' + id]" class="control-label">Status</label>
<select data-width="100%" v-model="row.status" :name="'rows['+id+'][status]'" :id="['status' + id]" class="select_picker" data-live-search="true" multiple >
<option value="Status 1">Status 1</option>
<option value="Status 2">Status 2</option>
</select>
</div>
</div>
<div class="col-xs-1">
<button type="button" class="btn btn_delete btn-xs btn-danger" v-on:click="delRow(id)">
<i class="fa fa-remove"></i> delete
</button>
</div>
</div>
</li>
</ul>
</div>
JS
app = new Vue({
el: '#app',
data: {
rows: []
},
methods: {
addRow: function () {
this.rows.push({startTime: '', endTime: '', status: []});
setTimeout(function () {
$('.select_picker').selectpicker('refresh');
$('.form_time').datetimepicker({format: 'LT'});
}.bind(this), 10);
},
delRow: function (id) {
this.rows.splice(id, 1);
}
},created:function() {
this.addRow();
}
});
This is the example : https://jsfiddle.net/rypLz1qg/9/
You really need to write a wrapper component. Vue expects to control the DOM and not to have you making DOM-changing things like the *picker calls at arbitrary times. However, a component gives you the opportunity to tell your component how to interact with the DOM in each of its lifecycle hooks so that its behavior can be consistent. See the JavaScript tab on the wrapper component example page.

How can I use a Knockout viewmodel inside a server loop?

I want to use Html helpers and Knockout to create a seamless transition of data from server to client, and then back to server again on postback.
My ViewModel has a few properties and then an array of items. I need to know how I can iterate over my array in ASP.NET Razor while assigning my knockout bindings to individual elements in the array.
Here's what I have so far:
#for (int i = 0; i < Model.Fields.Count; i++)
{
<div name="customFormField" data-bind="with: Fields[#i]">
<div class="form-group">
#Html.LabelFor(m => m.Fields[i].SqlDataType)
#Html.ListBoxFor(m => m.Fields[i].SqlDataType, new SelectList(selectDataTypeOptions), new { #class = "form-control", data_bind = "value: SqlDataType" })
</div>
</div>
}
My ko javascript:
<script>
function viewModel() {
this.addField = function() {
alert("wut");
}
}
$(function (){
var jsonModel = #Html.Raw(Json.Encode(Model));
var mvcModel = ko.mapping.fromJS(jsonModel);
var customFormTemplateViewModel = new viewModel();
var g = ko.mapping.fromJS(customFormTemplateViewModel, mvcModel);
ko.applyBindings(g);
});
</script>
When I browse the page, the only elements rendered are the <div name="customFormField" data-bind="with: Fields[x]"></div> elements, neither the form-group div inside it nor the label/listbox are created on the page.
There are no binding errors from KnockoutJS.
If I remove the data-bind="with: Fields[#i]", the other elements render properly, so it must be something about trying to bind to an element in an array that's making this go sideways, but I haven't been able to figure out what.
Edit: Here's the Html that is output from this:
It's interesting because if I inspect the DOM with chrome's inspector, it doesn't show anything inside each customFormField div, but in the source it does have the elements inside. It's outputting the System.Web.Mvc.SelectListItem in each item, but I think I just made my SelectList wrong.
<div name="customFormField" data-bind="with: Fields[0]">
<div class="form-group">
<label for="Fields_0__SqlDataType">SqlDataType</label>
<select class="form-control" data-bind="text: SqlDataType" id="Fields_0__SqlDataType" multiple="multiple" name="Fields[0].SqlDataType"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
</div>
</div>
<div name="customFormField" data-bind="with: Fields[1]">
<div class="form-group">
<label for="Fields_1__SqlDataType">SqlDataType</label>
<select class="form-control" data-bind="text: SqlDataType" id="Fields_1__SqlDataType" multiple="multiple" name="Fields[1].SqlDataType"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
</div>
</div>
<div name="customFormField" data-bind="with: Fields[2]">
<div class="form-group">
<label for="Fields_2__SqlDataType">SqlDataType</label>
<select class="form-control" data-bind="text: SqlDataType" id="Fields_2__SqlDataType" multiple="multiple" name="Fields[2].SqlDataType"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
</div>
</div>
<div name="customFormField" data-bind="with: Fields[3]">
<div class="form-group">
<label for="Fields_3__SqlDataType">SqlDataType</label>
<select class="form-control" data-bind="text: SqlDataType" id="Fields_3__SqlDataType" multiple="multiple" name="Fields[3].SqlDataType"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
</div>
</div>
<div name="customFormField" data-bind="with: Fields[4]">
<div class="form-group">
<label for="Fields_4__SqlDataType">SqlDataType</label>
<select class="form-control" data-bind="text: SqlDataType" id="Fields_4__SqlDataType" multiple="multiple" name="Fields[4].SqlDataType"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
</div>
</div>
Edit 2: This example is showing when I tried the text binding, but I've tried it both ways.
Edit 3: I copied the output Html into another place on the page, and it didn't render that either, until I removed the data-bind="with: Fields[n]" from the containing div, so the problem seems to be there. However, if I remove that from the parent in the actual file, I get a binding error from data-bind="value: SqlDataType"