How to use Vuelidate for an Object of an Array? - arrays

I have the following vue array;
server: [
{ id: 1, name: 'Name A', ipaddress: '192.168.1.1', status: true, applied: true, modal: false },
{ id: 1, name: 'Name A', ipaddress: '192.168.1.1', status: true, applied: true, modal: false },
]
I use this array to show these information on a data table. Users can add new rows to this table, that is, they can push the array. In addition, they can delete the rows they want from the table with the splice method. Finally, each row has an edit button. Since these buttons are connected to the elements in the array with the v-model, users can make changes on the row they want in the modal window that opens.
Adding and editing operations are carried out with two different modalities that open when the button is pressed.
In line with all this information, there is a question I want to ask. How can I write validation with Vuelidation to an array where new rpws can be added continuously? Here is my vuelidation functions;
validations: {
server: {
required,
$each: {
name: {
required
},
ipaddress: {
required
}
}
}
}
As an example, I just defined the required attribute for two elements. And here is how I use them in my add and edit modals;
<div>
<div">
<label>Name</label>
</div>
<div>
<label>:</label>
</div>
<div>
<input v-if="server[i].modal" v-model="server[i].name" type="text"/>
</div>
<small class="error-msg" v-if="!$v.server[i].name.required && $v.server[i].name.$dirty">Name is required.</small>
</div>
Here is how I add a new row to the table;
addNewRow(){
this.server.push({
name: "",
ipaddress: "",
status: true,
applied: false,
modal: false
});
},
And now I have this error;
[Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"
I think I'm missing an important part here so how can I make this correct? Thanks in advance.

Your add modal might be delay with the template so no server[i] item would be defined. I would suggest using a different variable for add (newItem = {name: '', ...})

Related

react-semantic-redux-form selectField multiple

I am attempting to use react-semantic-redux-form SelectField with the multiple options so a user can select multiple options and if there is one already set then this should show as checked.
I am also using redux-form with semantic0ui-react.
I am getting an error attempting to include multiple selections.
My include statement is:
import { SelectField } from "react-semantic-redux-form";
My state is:
state = {
relationships: ["some entry"],
relationshipOptions: [],
};
The element code is:
<Grid.Column>
<Field
component={SelectField}
name="relationships"
label="Your Relationships"
options={relationshipOptions}
multiple
placeholder="Select to add a relationship"
/>
I get the error as below
Dropdown `value` must be an array when `multiple` is set. Received type: `[object String]`.
in Dropdown
The way you have relationshipOptions is wrong, it is supposed array of objects,
const relationshipOptions = [
{ key: "single", value: "single", text: "single" },
{ key: "married", value: "married", text: "married" }
];
Here is the working example, Code Sandbox
Also if you have single, married in array. You can do something like this,
let relationshipOptions = ["single", "married"].map((x) => {
return ({
key: x,
value: x,
text: x
});
});

How do I preselect a vue-multiselect option when options is an array of objects?

I want to pre-select a particular value in a select drop-down generated by vue-multiselect.
I can get this to work fine if I have a simple array of strings like the following:
['Test 1', 'Test 2', 'Test 3']
However, when I use an array of objects, I can't get this to work. For example, if I have the following:
<v-multiselect :options="[{id: 1, name: 'Test 1'}, {id: 2, name: 'Test 2'}, {id: 3, name: 'Test 3'}]"
label="name"
track-by="id"
v-model="test">
</v-multiselect>
No matter what I set the test data property that v-model is connected to, it won't preselect the value. I've tried 1, 2, 3, '1', '2' and '3' for test when track-by is id and 'Test 1', etc. when track-by is name but nothing seems to work.
What am I doing wrong here? I looked at the docs at https://vue-multiselect.js.org/#sub-single-select-object, but they don't seem to provide an example when you want to preset a value for an array of objects for the options. Googling has also not returned what I'm looking for.
On a related topic, once I get this working, what would I have to change to select multiple values for when I set the component to multiple? Thank you.
track-by usage
The docs indicate that track-by is "Used to compare objects. Only use if options are objects."
That is, it specifies the object key to use when comparing the object values in options. The docs should actually state that track-by is required when the options are objects because <vue-multiselect> uses track-by to determine which options in the dropdown are selected and to properly remove a selected option from a multiselect.
Without track-by, you'd see two buggy behaviors for object-options: (1) the user would be able to re-select already selected options, and (2) attempting to remove selected options would instead cause all options to be re-inserted.
Setting initial values
<vue-multiselect> doesn't support automatically translating a value array, but you could easily do that from the parent component.
Create a local data property to specify track-by and initial multiselect values (e.g., named trackBy and initialValues, respectively):
export default {
data() {
return {
//...
trackBy: 'id',
initialValues: [2, 5],
}
}
}
Bind <vue-multiselect>.track-by to this.trackBy and <vue-multiselect>.v-model to this.value:
<vue-multiselect :track-by="trackBy" v-model="value">
Create a watcher on this.initialValues that maps those values into an object array based on this.trackBy, setting this.value to the result:
export default {
watch: {
initialValues: {
immediate: true,
handler(values) {
this.value = this.options.filter(x => values.includes(x[this.trackBy]));
}
}
}
}
Vue.component('v-multiselect', window.VueMultiselect.default);
new Vue({
el: '#app',
data () {
return {
trackBy: 'id',
initialValues: [5,2],
value: null,
options: [
{ id: 1, name: 'Vue.js', language: 'JavaScript' },
{ id: 2, name: 'Rails', language: 'Ruby' },
{ id: 3, name: 'Sinatra', language: 'Ruby' },
{ id: 4, name: 'Laravel', language: 'PHP' },
{ id: 5, name: 'Phoenix', language: 'Elixir' }
]
}
},
watch: {
initialValues: {
immediate: true,
handler(values) {
this.value = this.options.filter(x => values.includes(x[this.trackBy]));
}
}
}
})
<script src="https://unpkg.com/vue#2.6.6/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-multiselect#2.1.0"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-multiselect#2.1.0/dist/vue-multiselect.min.css">
<div id="app">
<v-multiselect :track-by="trackBy"
:options="options"
v-model="value"
label="name"
multiple>
</v-multiselect>
<pre>{{ value }}</pre>
</div>
Looks like a bug. The workaround is to use an actual reference to the object
Vue.component('v-multiselect', window.VueMultiselect.default);
let testOptions=[{id: 1, name: 'Test 1'}, {id: 2, name: 'Test 2'}, {id: 3, name: 'Test 3'}]
new Vue({
el: '#app',
data: function () {
return {
test: testOptions[1], // <- use an object ref here!
testOptions
};
}
});
The easiest way I found out is sending the whole object from BE, so it gets pre-selected. If you send the same object from BE will get pre-selected. But I don't know if your options are hard coded on FE or they are coming from a database or something. I had the same issue but my values were coming from my database, so it was easy to reproduce the object
In your question just :object="true" is missing actually they didn't know that it is of type string or object when we pass this it knows yes it is object and i need label="name" from v-model="test" and picks it and shows it as a preselected

VUEjs templates multiple selectboxes

So, I'm assigned to work with vue at work, but VUE and I aren't friends yet. Currently I'm facing an issue that I don't know how to resolve - I'll explain it the best I can with the limited VUE knowledge I possess.
Simplistically I have a vue component, which looks like this:
Vue.component('input-checkboxes', {
template: '#input_checkboxes',
props: ['id', 'label', 'list', 'required', 'readonly']
});
Then I have a template that looks like this:
<template id="input_checkboxes">
<div>
<div>{{ label }}</div>
<div>
<label v-for="list_item in list">
<input type="checkbox" v-model="value" :name="id" :required="required" :readonly="readonly" value="{{ list_item.name }}"> {{ list_item.name }}
</label>
</div>
</div>
</template>
Then I have a rather large vue instance that I'll paste the relevant parts of here.
This variable is being created:
var some_form = {
form : {
Endless: '',
Amounts: '',
Of: '',
Names: '',
In: '',
The: '',
Form: '',
THIS-ONE: ''
}
};
var vm = new Vue({
el: '#form_product',
data: $.extend({
someStuff : 'some values',
someLists : {}
}, some_form),
ready: function() {
this.getLists(); // Fetches alot of lists
},
methods: {
this.$http.get(
framework.url('api','getLookupLists')
).then(function (response) {
this.lists = response.body;
this.pageLoading = false;
}.bind(this));
}
In the end I have my html page that amongst loads of other fields, that works very well, has this:
<input-checkboxes
id="THIS-ONE"
label="A Fitting Label"
:value.sync="form.SomeID"
:list="lists.AnAppropriateList">
</input-checkboxes>
So, that's the gist of the setup. I have numerous other components like input-text, that works just fine (someone else made it before I did), I even created other components by copying his way, and just changing some elements.
I cannot get checkboxes to work, I think my problem is that there are numerous inputs, and that I don't know how to bind the results of those inputs to my VUE instance.
I really hope this makes sense, because I would really like some pointers on how to get on... Maybe if someone duplicated this setup really simplistic and showed how the array of values from the checkboxes could be bound to the vue instance?
There are a couple of mistakes you are (or might be) making.
First of all, the value prop you pass down has to be an array (seems
like it's a string from your example)
value is not correctly set, you need to set it by doing :value="someValue"; you can't have curlies in an attribute.
Lastly, value should probably be the id of the item and not the name. You have a chance of a collision if you use the name.
Bonus: you don't need to use :name at all (unless you are submitting the form server side...? But I can't see why you would do that.)
Here's a simple working example to sum this up:
HTML
<label v-for="list_item in list">
<input type="checkbox" v-model="value" :required="required" :readonly="readonly" :value="list_item.id"> {{ list_item.name }}
</label>
JS
var app = new Vue({
el: 'main',
data: function () {
return {
value: [],
label: 'Label name',
readonly: false,
required: true,
list: [
{
name: 'Item 1',
id: 'item1'
},
{
name: 'Item 2',
id: 'item2'
}
]
}
}
})
I've also made a bin for you to try it out.

AngularJS checkboxes checking from pivot table?

I created the following with the plugin: http://vitalets.github.io/checklist-model/
<section ng-repeat="owner in lord.owners">
<form ng-submit="foobar(owner)" name="update_location_form">
<input type="text" ng-model="owner.name">
<ul>
<li ng-repeat="sheep in sheeps">
<input checklist-model="owner.sheeps" checklist-value="sheep.id" type="checkbox">
<label class="checkbox">{{ sheep.name }}</label>
</li>
</ul>
<button type="submit">Submit</button>
</form>
</section>
All sheeps are shown in the list. And saving to my pivot table (manytomany-relation) also works.
But when I refresh the page, all checks are gone of course. How can I access them?
They're stored in:
{
id: 1,
name: "Obama",
farms: [
{
id: 10,
name: "VirtualFarm",
sheeps: [
{
id: 1,
name: "Foo",
},
{
id: 2,
name: "Bar",
},
{
id: 10,
name: "Cow",
},
{
id: 13,
name: "Hey",
},
]
}
]
}
But I really have now clue how I can check the checkboxes by default that are in the Pivot table.
Someone?
The checklist-model directive automatically checks the appropriate checkboxes based on the value of the checklist-model. You don't have to do anything else, your code looks fine. But ...
First of all, I suspect that owner in lord.owners must be something like owner in x.farms where x is the object that you pasted above.
And this is on the client side and even though you check this boxes, you still need to save them on the server-side. On a refresh, every data not persisted on the server side is lost.

AngularJS: Binding boolean value to radio button such that it updates model to false on uncheck event

In my AngularJS application, I am displaying contacts data in a grid. My typical contacts JSON looks like as below ...
[
{ type: "IM", value: "mavaze123", default: true },
{ type: "IM", value: "mvaze2014", default: false },
{ type: "IM", value: "mavaze923", default: false },
{ type: "IM", value: "mvaze8927", default: false },
{ type: "Email", value: "mavaze123#abc.com", default: true },
{ type: "Email", value: "mvaze2014#xyz.net", default: false }
]
The last property 'default' is actually a radio button, selection of which should alter the original default value of the corresponding contact type in above JSON. There can be one default from each type of contact i.e. we can group radio buttons based on the contact type.
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true"/></div>
</div>
Note: The above code is not the exact one, but approximately same, as
it will appear inside a custom grid component.
Now when I load my view/edit form page with above JSON, it correctly shows the radio state of all contacts. The problem comes, after page load, when user selects another contact as default. This actually changes the model value of default to true for newly selected contact however the model value of original default contact still remains true, even though its radio state changes to uncheck/blur (because they are having same 'name' value).
I thought to write a directive, but I am unable get it triggered on radio on-blur/uncheck event.
There are various posts on binding boolean values to radio buttons, but I am unable to get it work in my scenario, as I want to update model values for individual radio button in a radio group. See there is no single model representing a radio group.
I think you should change your design to separate the contacts from contactTypes and store the key to the default contact in contact type.
In your current design, there are duplicated values for default and that's not the desired way to work with radio.
$scope.contacts = [
{ type: "IM", value: "mavaze123" },
{ type: "IM", value: "mvaze2014" },
{ type: "IM", value: "mavaze923" },
{ type: "IM", value: "mvaze8927" },
{ type: "Email", value: "mavaze123#abc.com" },
{ type: "Email", value: "mvaze2014#xyz.net" }
];
$scope.contactTypes = {
"IM": { default:"mavaze123"}, //the default is contact with value = mavaze123
"Email": { default:"mavaze123#abc.com"}
};
You Html:
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contactTypes[contact.type].default" ng-value="contact.value"/></div>
</div>
DEMO
I assume that the key of contact is value, you could use an Id for your contact.
I added an attribute directive in my input statement ...
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true" boolean-grid-model /></div>
</div>
And my custom directive ...
myModule.directive('booleanGridModel') {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
var radioSelected = scope.$eval(attrs.ngModel);
if(radioSelected) {
var selectedContact = scope.contact;
_.each(scope.contacts, function(contact) {
if(contact.type === selectedContact.type) {
_.isEqual(contact, selectedContact) ? contact.default = true : contact.default = false;
}
});
}
}
};
}
WHy you declare ng-value="true" please remove that
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="{{contact.default}}"/></div>
Please use $scope.$apply() in your value changing code
Like something below
$scope.$apply(function ChangeType()
{
/Code
});
And you need to change name="{{contact.type}}" to name="contact.type{{$index}}" Because some types are same name.

Resources