VueJS bind select to object but still POST string - vue.js

What is the correct way to bind a select element to an object (rather than a string value) but still have the HTML element submit a string value?
I've managed to get this working, but it almost seems like I'm exploiting a bug:
<select v-model="selected" v-on:change="price=selected.price">
<option v-for="item in items" v-bind:value="item" value="{{ item.id }}">{{ item.name }}</option>
</select>
This works as intended: the "selected" property is attached to the "item" object, but the form POSTs just the item's ID. However, if I reverse the order of the HTML attributes, so that value={{ item.id }} comes before v-bind:value="item", then the form POSTs "[Object]" rather than, e.g., "3".
The fact that it's so fragile makes me think I'm doing something wrong.
So what's the right way to handle this?

I had a similar situation in which I built several vue components that could be used both within a vue component or within a standard form.
<select v-model="selected" v-on:change="price=selected.price">
<option v-for="item in items" :value="JSON.stringify(item)">{{ item.name }}</option>
</select>
Appears to be what you are after. I also had success using a computed property or filter but I decided that stringify was most readable.

I fixed it by using this approach:
<select v-model="product">
<option v-for="obj in choices" :value="obj">{{ obj.name }}</option>
</select>
<input type="hidden" name="product" :value="choice.id">
In summary: don't give your select a name but give that name to your hidden input and provide the ID as value on that element instead.

I see in both the cases, HTML being rendered as following:
<select>
<option value="[object Object]">name1</option>
<option value="[object Object]">name2</option>
<option value="[object Object]">name3</option>
<option value="[object Object]">name4</option>
</select>
Case 1 : v-bind:value="item" value="{{ item.id }}" : fiddle
Case 2 : value="{{ item.id }}" v-bind:value="item" : fiddle
So both the cases are equivalent as far as HTML being rendered. Ideal way to do it without confusion will be just using v-bind:value="item" like following:
<select v-model="selected" v-on:change="price=selected.price">
<option v-for="item in items" v-bind:value="item">{{ item.name }}</option>
</select>
You should v-bind to item or item.id depending on what you want to assign to selected variable.

Related

v-model and selected is not working at the same time... --vue.js

UPDATED
select input's selected option is not working if I use v-model on select.
<p class="topics">fruits</p>
<select class="select" v-model="selectFruit">
<option selected value="">--all--</option>
<option :key="index" :value="item" v-for="(item,index) in fruitList">{{item}}</option>
</select>
if I don't use v-model, then selected is working. But I need that v-model bind for filter my array. But it looks like I can't use v-model and selected at the same time.
Use selected attribute
https://www.w3schools.com/tags/att_option_selected.asp
<select class="select" v-model="searchCity">
<option value="" selected>--全部--</option>
<option :value="item" v-for="item in uniqueCity">{{item}}</option>
</select>
Adding a bonus to the above answer, if you want to have a default placeholder but not a valid value (Like "Select country here") you can do it like this:
<select>
<option value="" selected disabled hidden>Select country here</option>
<option value="1">Bulgaria</option>
<option value="2">Serbia</option>
<option value="3">Cyprus</option>
</select>

Filtering with Vue.js, getting the value of an Object

I have a website that uses a filtering system built in Vue.js, it filters properties with "states", "cities" and "type", the code looks like this, it works for states and types but not for cities which come from an Object rather than an Array. I am not sure how to acces the value inside of the Object.
<div class="grid-x grid-margin-x">
<div class="cell medium-auto">
<label for="property-state">STATE</label>
<select name="property-state" #change="search()" id="property-state">
<option value="">Select</option>
<option v-for="val in terms['property-state']" :value="val.id">{{ val.name }}</option>
</select>
</div>
<div class="cell medium-auto">
<label for="city">CITY</label>
<select name="city" #change="search()" id="city">
<option value="">Select</option>
<option v-for="val in terms ['location']" :value="val.id">{{ val.city }}</option>
</select>
</div>
<div class="cell medium-auto" #change="search()">
<label for="property-type">PROPERTY TYPE</label>
<select name="property-type" id="property-type">
<option value="">All types</option>
<option v-for="val in terms['property-type']" :value="val.id">{{ val.name }}</option>
</select>
</div>
</div>
I am aware that I'm trying to access "location" as if it were an Array but not sure how to do it as it is an Object as seen in the image attached.
The data I am trying to access is structured as follows:
location (Object)
|
city: "cityName"
In Vue, v-for treats an object and an array in the same way. An array has the same type of values, but an object has a structure that could be different. Use computed properties to save your city name into an array.
https://v2.vuejs.org/v2/guide/list.html#v-for-with-an-Object

How can I add a disabled option when populating a select with Vue.js v-for

I would like to add a disabled option to a select that I have bound with v-for binding. The Vue docs on select suggests adding one but the example is using hard coded options.
I want to create a disabled 'Please select one' with v-for binding to force the user to pick a option rather than defaulting to a particular selection. I currently add a 'Please select one' option to the list I'm binding the select to and it shows up and works fine but I don't want the user to be able to choose it again.
How can I accomplish this when using v-for binding to a select?
//Contrived example of adding the default selection text
data.dashboardDefinitionList.splice(0, 0, { Id: 0, Name:"Select a Dashboard" });
<select id="dashboardSelectNew" v-model="formVariables.dashboardDefIndex" v-on:change="getDashboard">
<option v-for="(dd, index) in dashboardDefinitionList"
:value="dd.Id"
:selected="formVariables.dashboardDefIndex == index">
{{ dd.Name }}
</option>
</select>
Put your disabled option first, then do the v-for.
<select id="dashboardSelectNew" v-model="formVariables.dashboardDefinition" #change="getDashboard">
<option disabled value="">Please select one</option>
<option v-for="dd in dashboardDefinitionList" :key="dd.id" :value="dd">
{{ dd.Name }}
</option>
</select>
Note that I've also attempted to clean up your model / value binding but you may not want or need it.
For the initial value, you would set it to an actual entry from your list instead of a specific index, eg
this.formVariables.dashboardDefinition = this.dashboardDefinitionList[someIndex]
You can use it like this adding disabled selected to appear first and cannot be selected also good practice to put value="0" because you are using id in the value attribute
<select id="dashboardSelectNew" v-model="formVariables.dashboardDefIndex" v-on:change="getDashboard">
<option value="0" disabled selected> Please select one </option>
<option v-for="(dd, index) in dashboardDefinitionList"
:value="dd.Id"
:selected="formVariables.dashboardDefIndex == index">
{{ dd.Name }}
</option>
</select>

How to bind v-model with select if i have foreach in foreach?

When i alert(this.property_credentials.district) in vue.js i get empty
<select v-model="property_credentials.district" name="district" class="country selectpicker" id="selectCountry" data-size="10" data-show-subtext="true" data-live-search="true">
<option value="0">--Please select your district</option>
#foreach($districts as $district)
<optgroup label="{{$district->district}}">
#foreach($district->regions as $region)
<option value={{ $region}} {{ (old("district") == $region? 'selected':'') }}>{{ $region}}</option>
#endforeach
</optgroup>
#endforeach
How can i pass this value $region to vue.js ?
The syntax of looping is wrong, there is no #foreach in vuejs, you will have to use v-for to loop in the template. It should be something like:
<select v-model="property_credentials.district" name="district" class="country selectpicker" id="selectCountry" data-size="10" data-show-subtext="true" data-live-search="true">
<option value="0">--Please select your district</option>
<div v-for="district in $districts">
<optgroup label="{{district->district}}">
<div v-for="region in district.regions">
<option value={{region}} {{ (old("district") == region? 'selected':'') }}>{{ $region}}</option>
</div>
</optgroup>
</div>
You are mixing two different syntax together, you are using blade code with VueJs. data binding will be wrong.
What you need to do is to bind the value from laravel to a variable that vuejs can consume, something like this
Laravel blade
<script>
// this must be a json value
window.districts = {{$districts}}
</script>
In your VueJS code you need to bind this value to your data array, then you can use it

Vue js recognize selected option

I have cities object which contains city.name and city.id. Also I have cameras object which has city_id: cameras.city_id. In my html:
<div v-for="camera in cameras">
<select v-model="camera.city_id" class="form-control">
<option v-for="city in cities" selected>#{{ city.name }}</option>
</select>
</div>
I have to recognize which element of object should be marked as selected, simply said mark element as selected if city.id == camera.city_id. It will be true only once per loop. How do I manage that? Thanks.
You should be using value on the options like this:
<div v-for="camera in cameras">
<select v-model="camera.city_id" class="form-control">
<option v-for="city in cities" :value="city.id">#{{ city.name }}</option>
</select>
</div>
Done that way, the proper option will automatically be selected for you by the v-model directive.
See this for more information: http://vuejs.org/guide/forms.html#Select