VUEjs templates multiple selectboxes - checkbox

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.

Related

How to use Vuelidate for an Object of an Array?

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: '', ...})

Using angularjs how can I get checked and unchecked values

Here I am binding values to ng-click as
<input type="checkbox" ng-model="a.CheckAssign"ng-click="myFunctionnew(a.ENQUIRY_CODE,a.CheckAssign)" />
enquiryArr=[]
$scope.myFunctionnew = function(enqcode,checkassign)
{
enquiryArr.push(enqcode + '&' + checkassign)
var uniqueNames = [];
$.each(enquiryArr, function (i, el) {
if ($.inArray(el, uniqueNames) === -1) {
uniqueNames.push(el);
console.log(uniqueNames)
}
else
{
console.log(uniqueNames);
}
}
Here when I check and uncheck the checkbox the value is storing multiple
Please help me how can I store Enquiry code and T/F values.
If I understand your issue correctly, you're running into duplicate entries in your enquiryArr. You're running into this because you're trying to manually keep track of the array in an odd fashion. While there are ways to correct the way you're storing it, it's even easier to have angular track what is checked and what is not.
Using the following DataSet:
$scope.enquiries = [
{ENQUIRY_CODE: 'ENQUIRY_1', ENQUIRY_NAME: 'First Enquiry', selected: false},
{ENQUIRY_CODE: 'ENQUIRY_2', ENQUIRY_NAME: 'Second Enquiry', selected: false},
{ENQUIRY_CODE: 'ENQUIRY_3', ENQUIRY_NAME: 'Third Enquiry', selected: false},
{ENQUIRY_CODE: 'ENQUIRY_4', ENQUIRY_NAME: 'Fourth Enquiry', selected: false}
];
And binding the selected field to your checkboxes ng-model
<div ng-repeat="e in enquiries">
<input type="checkbox" ng-model="e.selected" />
{{e.ENQUIRY_NAME}}
</div>
You can determine which one is checked simply by looking at the $scope.enquiries array and looking for selected: true (or false if you want to know the ones not checked).
In javascript you can use a simple Array Filter to get the selected values as such:
$scope.enquiries.filter(e => e.selected);
Or if you want to get them in your template, you can also use the filter pipe as such:
{{(enquiries | filter:{selected:true})}}
Here is an interactive plunkr that you can view this.
Misc Note: If you do want to run something when the checkbox is clicked, you can still use an ng-click and run your custom code, however, I would recommend using ng-change as there are other ways to change the selected value of a checkbox other than clicking.
I have test your code and its working fine. your problem is not so much clear so you can check following test code.
<div ng-controller="MyController">
<div ng-repeat="dt in data">
<input type="checkbox" ng-model="CheckAssign" ng-click="myFunctionnew(dt.name,dt.volume)" />
</div>
</div>
Javascript
$scope.myFunctionnew = function(enqcode,checkassign)
{
enquiryArr.push(enqcode + '&' + checkassign)
var uniqueNames = [];
for(i=0; i <enquiryArr.length; i++) {
if ($.inArray(enquiryArr[i], uniqueNames) == -1) {
uniqueNames.push(enquiryArr[i]);
console.log(uniqueNames)
}
else
{
console.log(uniqueNames);
}
}
}
JSFiddle

How to update Angular scope properties when they are passed into directives?

I have functionality where developers can add custom Angular views where they can bind properties to the $scope.settings object. When clicking on the save button the $scope.settings object will be converted to JSON and saved to the database. Something like this will be the result:
{
"name": "bob",
"age": "25"
}
As long as I add elements like <input type="text" ng-model="settings.name" /> everything goes as expected.
But, now I want to add directives like this:
<umb-property property="property in properties">
<umb-editor model="property"></umb-editor>
</umb-property>
With the following code:
$scope.properties = [
{
label: 'Name',
alias: 'name',
view: 'textbox',
value: $scope.settings.name
},
{
label: 'Age',
alias: 'age',
view: 'number',
value: $scope.settings.age
}
];
The 'editor' directive loads views in place based on the 'view' property. The views are third party. The editors are loaded in a dialog. After submission of the settings dialog, the following line of code will convert the settings to JSON:
$scope.dialog = {
submit: function (model) {
var settingsJson = JSON.stringify(model.settings);
},
close: function (oldModel) {
//
}
};
In this case I cannot parse the $scope.settings to JSON, because the $scope.settings.name is not updated anymore. The $scope.editorModel.value was updated instead.
How can I bind the $scope.editorModel.value to $scope.settings.name?
I don't want to end up with a solution where I must update all $scope.settings values with the corresponding values from the editor models, because I want to support the dynamic way to convert the $scope.settings to a JSON value in the database.
For example I dont want to do: $scope.settings.name = $scope.properties[0].value
Use property accessors:
for (var i=0; i<$scope.properties.length; i++) {
$scope.settings[$scope.properties[i].alias] = $scope.properties[i].value;
};
HTML
<div ng-repeat="prop in properties">
<input ng-model="prop.value">
</div>

Ng-click filter between 2 scopes

I am new to Angular.js so I am not sure if this is the right approach. I have two scopes that are used to display 2 sets of buttons. The second set should be dependent on the button I click in the first set.
<!-- Insulation placement -->
$rootScope.roofs = [
{
type: 'roof',
label: 'Pitched Roof'
},
{
type: 'attic',
label: 'Floor of Attic'
}
];
<!-- Roof insulation types -->
$rootScope.roofInsulation = [
{
target: 'roof',
type: 'between_rafters',
label: 'Between Rafters'
},
{
target: 'roof',
type: 'between_rafters_counter_batten',
label: 'Between Rafters With A Counter Batten'
},
{
target: 'roof',
type: 'between_rafters_calibel',
label: 'Between Rafters With Calibel'
},
{
target: 'roof',
type: 'between_rafters_thermal_laminate',
label: 'Between Rafters With Thermal Laminate'
},
{
target: 'attic',
type: 'test',
label: 'Test'
}
];
and my HTML
<div ng-repeat="types in roofs">
<button ng-click="myFilter = {target: '{{types.type}}'}" class="btn btn-primary" type="button">{{types.label}}</button>
</div>
<div>
<button ng-repeat="variants in roofInsulation | filter: myFilter" class="btn btn-secondary" type="button">{{variants.label}}</button>
</div>
I realize that myFilter in the ng-click is a bit of a hack, but aside from that I can't get it to filter the results of ng-repeat. The myFilter variable does return the proper result {target: 'roof'} (for the first button). Do I assume correctly that it's because the first set of buttons is in a different scope than the second one?
You are not really using 2 different scopes here. If you had been using 2 different controllers or different directives then you would have got 2 different scopes. You are using $rootScope which is common across the entire angular app.
The reason myFilter is not working is because angular is unable to parse the expression in ng-click correctly, it's better you write a method (exposed to the scope) and change the value of myFilter in the method. It's a good practice as well as a better way to achieve what you are trying to do.
HTML
<button ng-click="setFilter(types)" class="btn btn-primary" type="button">{{types.label}}</button>
JS
$rootScope.setFilter = function(types) {
$rootScope.myFilter = {target: types.type};
}
Check this fiddle here, I have created a working example based on your code.
EDIT
Even if your target variable is an array there shouldn't be any issue because Anguar's pipe filter will take care of it.
I have updated and created a new fiddle to show it, check it here.
So if target is an array having 2 values - ['roof', 'attic'], that particular element will be shown for both the buttons.

How come my two nodes with the same model have different values?

I have a angular-template that looks like this:
<div class="radiobutton" ng-repeat="mylabel in field.labels">
<input
type="radio"
name="{{field['key']}}"
value="{{mylabel.label}}"
id="{{mylabel.name}}"
ng-model='my_radio_button'
ng-class='my_radio_button'
>
<label for="{{field['key']}}">
{{mylabel.label}}
</label>
</div>
and a scope that looks like this:
{
key: 'entry.1602323871',
type: 'radio',
labels:
[
{
name: 'media',
label: 'Media'
},
{
name: 'frilans',
label: 'Frilans'
}
],
}
I expect that once I click the first radio-button, both of theese elements should get the class "Media" and once I click the second one, they should both get the class "Frilans", because they share the same model, but when I click the media-element that element get the class Medida, and when I click on frilans that element get's the class frilans, the class isn't removed when I click the other element either. Why?
By using $parent.my_radio_button you access the parent scope rather than the single scope that is created for every single loop.

Resources