v-model for dynamically generated checkboxes - javascript

Here is my fiddle : DEMO
modules: [{
moduleName: "Module ABC",
id: 1,
actions: [{
actionName: "addbrand",
id: 1,
permissions: [{
permissionName: "read",
"id": 1,
"value": true
}, {
permissionName: "write",
"id": 2,
"value": true
}, {
permissionName: "execute",
"id": 1,
"value": false
}]
}]
Checkboxes are dynamically generated iterating over "modules" array in data object. But I am finding it difficult to assign v-model and capture the checked values for the corresponding "action" for its respective "module"'
How do I do this?
<div v-for="module in modules"><b>{{ module.moduleName }}</b>
<div v-for="action in module.actions">{{ action.actionName }}
<div v-for="permission in action.permissions">
<input type="checkbox"> {{ permission.permissionName }}
</div>
</div>
<hr>
</div>
Any help would be much appreciated. Thank you..

I am not sure having nesting more than 2 v-for is a good idea. But you can create an index in v-for as: <p v-for='(foo, index) in array' and use the index to track changes.
In you case you do something like this https://jsfiddle.net/samayo/az9hge7u/5/
new Vue({
el: '#app',
data: {
modules: [{
moduleName: "Module ABC",
id: 1,
actions: [{
actionName: "addbrand",
id: 1,
permissions: [{
permissionName: "read",
"id": 1,
"value": true
}, {
permissionName: "write",
"id": 2,
"value": true
}, {
permissionName: "execute",
"id": 1,
"value": false
}]
}, {
actionName: "addproduct",
id: 2,
permissions: [{
permissionName: "read",
id: 1,
value: true
}, {
permissionName: "write",
id: 2,
value: true
}, {
permissionName: "execute",
id: 1,
value: false
}]
}]
}, {
moduleName: "Module PQR",
id: 2,
actions: [{
actionName: "addrules",
id: 3,
permissions: [{
permissionName: "read",
id: 1,
value: true
}, {
permissionName: "write",
id: 2,
value: true
}, {
permissionName: "execute",
id: 1,
value: false
}]
}, {
actionName: "addactions",
id: 4,
permissions: [{
permissionName: "read",
id: 1,
value: true
}, {
permissionName: "write",
id: 2,
value: true
}, {
permissionName: "execute",
id: 1,
value: false
}]
}]
}]
}
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<div v-for="(module, moduleIndex) in modules"><b>{{ module.moduleName }}</b>
<div v-for="(action, actionIndex) in module.actions">{{ action.actionName }}
<div v-for="(permission, permIndex) in action.permissions">
<input type="checkbox" v-model='modules[moduleIndex].actions[actionIndex].permissions[permIndex].value'> {{ permission.permissionName }} - {{modules[moduleIndex].actions[actionIndex].permissions[permIndex].value}}
</div>
</div> <hr>
</div>

https://jsfiddle.net/srinivassunkari/t2fjzLpn/29/
1 Because of mutation no need to use the index to update the values of permission 'value'
2 When you use v-model it updates the value of the permission in the module.action.
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="module in modules"><b>{{ module.moduleName }}</b>
<div v-for="action in module.actions">{{ action.actionName }}
<div v-for="permission in action.permissions">
<input type="checkbox" v-model="permission.value">
{{ permission.permissionName }}
</div>
</div>
<hr>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
modules: [{
moduleName: "Module ABC",
id: 1,
actions: [{
actionName: "addbrand",
id: 1,
permissions: [{
permissionName: "read",
"id": 1,
"value": true
}, {
permissionName: "write",
"id": 2,
"value": true
}, {
permissionName: "execute",
"id": 1,
"value": false
}]
}]
}]
}
},
// for understanding purpose added no need to consider this...
watch: {
modules: {
deep: true,
handler(modules) {
console.log('modules', modules)
}
}
}
})
</script>

Related

Vuejs get dynamic form all values

I have select and input component with made by buefy. Everything is ok till I realize how can I get the data.
I'm sort of new on vuejs. So I will be glad if you help me out.
Maybe I can do with Javascript but how?
I'm getting dynamic form from backend
Here is my codes;
Input.vue
<template>
<b-field :label="fieldLabel">
<b-input
:name="inputName"
:type="inputType"
:maxlength="inputType == 'textarea' ? 200 : null"
></b-input>
</b-field>
</template>
<script>
export default {
name: "Input",
props: {
inputType: {
type: String,
required: true,
default: "text",
},
inputName: {
type: String,
required: true,
},
fieldLabel: {
type: String,
required: true,
}
}
};
</script>
Home.vue
<template>
<div class="container is-max-desktop wrapper">
<div v-for="element in offer" :key="element.id">
<Input
v-model="element.fieldValue"
:fieldLabel="element.fieldLabel"
:inputType="element.fieldType"
:inputName="element.fieldName"
v-if="element.fieldType != 'select'"
class="mb-3"
/>
<Select
v-model="element.fieldValue"
:fieldLabel="element.fieldLabel"
:options="element.infoRequestFormOptions"
:selectName="element.fieldName"
v-if="element.fieldType == 'select'"
class="mb-3"
/>
</div>
<b-button type="is-danger" #click="getOffer()">GET</b-button>
</div>
</template>
<script>
import axios from "axios";
import Select from "../components/Select.vue";
import Input from "../components/Input.vue";
export default {
name: "Home",
data() {
return {
offer: [],
};
},
components: {
Select,
Input,
},
methods: {
getOfferForm() {
axios({
method: "get",
url: `/GETDYNAMICFORM`,
})
.then((response) => {
this.offer = response.data;
})
.catch(() => {
this.$buefy.toast.open({
duration: 3000,
message: "oops",
position: "is-bottom",
type: "is-danger",
});
});
},
getOffer() {
console.log(this.offer);
},
},
created() {
this.getOfferForm();
},
};
</script>
Example Dynamic Form Response like;
[ { "id": 58, "fieldLabel": "Name Surname", "providerLabel": "Name
Surname", "fieldName": "nmsrnm", "fieldType": "text", "fieldValue":
null, }, { "id": 60, "fieldLabel": "E-mail", "providerLabel":
"E-mail", "fieldName": "e_mail_60", "fieldType": "email",
"fieldValue": null, }, { "id": 2, "fieldLabel": "Budget",
"providerLabel": "Budget", "fieldName": "bdget", "fieldType":
"select", "fieldValue": "", "infoRequestFormOptions": [ { "id": 1,
"orderNum": 0, "optionValue": 0, "optionText": "Select", "minValue":
null, "maxValue": null }, { "id": 2, "orderNum": 1, "optionValue": 1,
"optionText": "10-30", "minValue": 10, "maxValue": 30 } ] } ]

Display data from an Api in a v-data-table, an object within an object vue js, vuetify

I have the following Json coming from an api, which I want to present in a V-DATA-TABLE:
[
{
"id": 1,
"firstName": "Ana",
"lastName": "Lucia",
"phone": "(11)99989-8989",
"mobilePhone": "(11)99989-8989",
"email": "aninha#gmail.com",
"gender": {
"name": "feminino"
},
"status": {
"name": "inativo"
},
"services": [
{
"name": "progressiva"
},
{
"name": "Manicure"
}
]
},
{
"id": 2,
"firstName": "Maria",
"lastName": "Luiza",
"phone": "(12)32333-3333",
"mobilePhone": "(43)45555-5555",
"email": "marialu#gmail.com",
"gender": {
"name": "feminino"
},
"status": {
"name": "pendente"
},
"services": [
{
"name": "progressiva"
}
]
},
{
"id": 3,
"firstName": "Mario",
"lastName": "Braz",
"phone": "(11)23232-3222",
"mobilePhone": "(11)23232-3222",
"email": "mariobraz#gmail.com",
"gender": {
"name": "masculino"
},
"status": {
"name": "ativo"
},
"services": [
{
"name": "progressiva"
}
]
}
]
However in the Data table the field that the Services would come from, is empty as shown in the image:
Here is the code of my .Vue data:
data: () => ({
dialog: false,
pageTitle: 'Employees',
headers: [
{
text: 'First Name',
align: 'start',
sortable: false,
value: 'firstName',
},
{ text: 'Last Name', value: 'lastName' },
{ text: 'Email', value: 'email' },
{ text: 'Phone', value: 'phone' },
{ text: 'Mobile Phone', value: 'mobilePhone' },
{ text: 'Gender', value: 'gender.name' },
{ text: 'Status', value: 'status.name' },
{ text: 'Services', value: 'services.name' },
{ text: 'Actions', value: 'action', sortable: false },
],
search: '',
employees: [],
genders: [],
status: [],
services:[],
editedIndex: -1,
editedItem: {},
defaultItem: {},
}),
I noticed that when I change this code snippet and leave only 'services':
{ text: 'Services', value: 'services' },
exactly the number of objects that are the services appears but not the names:
Here is the method I used to pull the main object that is the 'employees' and all their relationships:
methods: {
initialize () {
axios.get('http://192.168.26.130:3000/employees/').then(response => {
this.employees = response.data
console.log(response)
}).catch(e => {
console.log(e)
});
axios.get('http://192.168.26.130:3000/genders/').then(response => {
this.genders = response.data
console.log(response)
}).catch(e => {
console.log(e)
});
axios.get('http://192.168.26.130:3000/employee-status').then(response => {
this.status = response.data
console.log(response)
}).catch(e => {
console.log(e)
});
axios.get('http://192.168.26.130:3000/services').then(response => {
this.services = response.data
console.log(response)
}).catch(e => {
console.log(e)
});
},
{ text: 'Services', value: 'services.map(s => s.name).join(", ") }
will display the services names, separated by ', ' (comma + space).
Alternative method, using template:
<template v-slot:item.services="{ item }">
{{ item.services.map(s => s.name).join(', ') }}
</template>
services prop is an array:
"services": [
{
"name": "progressiva"
},
{
"name": "Manicure"
}
]
If you want to display the first value, write:
{ text: 'Services', value: 'services[0].name' },
Otherwhise, you need to transform the array.

Filtering out objects of a deeply nested data structure in Typescript / Javascript

I want to filter out of a deeply nested data structure all the objects that match a rule. I know there are similar examples to delete a particular key of nested object, but I haven't been able to implement the solutions. The data structure will never be infinite, but it can be very deep (more than 10 levels)
Here are the types:
export type DataStructure = Entry[]
export interface Entry {
id: string
text: string
type: 1 | 2
children?: Entry[]
}
So an entry array could be:
[
{
id: "1",
type: 1,
text: "Node 1",
children: [
{
id: "1.1",
type: 1,
text: "Node 1.1",
children: [
{
id: "1.1.1",
type: 2,
text: "Node 1.1.1",
children: []
}
],
},
{
id: "1.2",
type: 1,
text: "Node 1.2",
children: [
{
id: "1.2.1",
type: 2,
text: "Node 1.2.1",
children: [],
},
{
id: "1.2.2",
type: 1,
text: "Node 1.2.2",
children: [],
}
]
}
]
}
]
The expected output array, provided the rule type !== 2 would be:
[
{
id: "1",
type: 1,
text: "Node 1",
children: [
{
id: "1.2",
type: 1,
text: "Node 1.2",
children: [
{
id: "1.2.2",
type: 1,
text: "Node 1.2.2",
children: [],
}
]
}
]
}
]
I haven't been able to implement recursion to do it, the arrays keep showing all the entries
I don't mind using lodash if there is a built-in function. Thanks!
If you want to filter based on type:
function test() {
const test = [
{
id: "1",
type: 1,
text: "Node 1",
children: [
{
id: "1.1",
type: 1,
text: "Node 1.1",
children: [
{
id: "1.1.1",
type: 1,
text: "Node 1.1.1",
children: []
}
],
},
{
id: "1.2",
type: 2,
text: "Node 1.2",
children: [
{
id: "1.2.1",
type: 2,
text: "Node 1.2.1",
children: [],
},
{
id: "1.2.2",
type: 2,
text: "Node 1.2.2",
children: [],
}
]
}
]
}
];
console.log(JSON.stringify(filterData(test, 2), 0, 4))
console.log('test: ', test);
}
and filter method:
function filterData(data, type) {
var r = data.filter(function(o) {
if (o.children)
o.children = filterData(o.children, type);
return o.type != type
})
return r;
}

javascript iterate over objects in nested array of objects and filter by ids and return the same original dataset updated

I have an array of nested objects, that i want to keep the objects in items that have the id equal to one in the filter list that i have as reference.
const data = [{
"otherStuff": "otherB",
"items": {
"item1": [{
"id": "id1",
"info": "info1"
},
{
"id": "id2",
"info": "info22"
}
],
"item20": [{
"id": "id3",
"info": "info5"
}],
"item5": [{
"id": "id4",
"info": "info6"
},
{
"id": "id5",
"info": "info7"
}
]
}
}, {
"otherStuff": "otherA",
"items": {
"item1": [{
"id": "id1",
"info": "info10000"
},
{
"id": "id2",
"info": "info220000"
}
],
"item20": [{
"id": "id3",
"info": "info5000"
}],
"item5": [{
"id": "id4",
"info": "info60000"
},
{
"id": "id5",
"info": "info7000"
}
]
}
}];
const keep = ['id4', 'id2'];
keep.forEach(function(val) {
data.forEach(function(entry, index){
const entrySelected = [];
Object.keys(entry.items).forEach(item => {
var match = entry.items[item].find(obj => obj.id === val);
if (match) {
entrySelected.push(match)
}
});
data[index].items = entrySelected;
});
})
console.log(data)
I am getting an error right now,
but the idea is to get the following output:
[
{
"otherStuff": "otherB",
"items": [
{
"id": "id2",
"info": "info22"
},
{
"id": "id4",
"info": "info6"
}
]
},
{
"otherStuff": "otherA",
"items": [
{
"id": "id2",
"info": "info220000"
},
{
"id": "id4",
"info": "info60000"
}
]
}
]
how can i achieve this?
You could iterate the values of the objects and then reduce the wanted items for a new array. Later assing this to items.
var data = [{ otherStuff: "otherB", items: { item1: [{ id: "id1", info: "info1" }, { id: "id2", info: "info22" }], item20: [{ id: "id3", info: "info5" }], item5: [{ id: "id4", info: "info6" }, { id: "id5", info: "info7" }] } }, { otherStuff: "otherA", items: { item1: [{ id: "id1", info: "info10000" }, { id: "id2", info: "info220000" }], item20: [{ id: "id3", info: "info5000" }], item5: [{ id: "id4", info: "info60000" }, { id: "id5", info: "info7000" }] } }],
keep = ['id4', 'id2'];
data.forEach(o =>
o.items = Object
.keys(o.items)
.reduce((r, k) => o
.items[k]
.reduce((s, p) => s.concat(keep.includes(p.id) ? p : []), r), []));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
With a filter for arrays.
var data = [{ otherStuff: "otherB", items: { item1: [{ id: "id1", info: "info1" }, { id: "id2", info: "info22" }], item20: [{ id: "id3", info: "info5" }], item5: [{ id: "id4", info: "info6" }, { id: "id5", info: "info7" }] } }, { otherStuff: "otherA", items: { item1: [{ id: "id1", info: "info10000" }, { id: "id2", info: "info220000" }], item20: [{ id: "id3", info: "info5000" }], item5: [{ id: "id4", info: "info60000" }, { id: "id5", info: "info7000" }] } }],
keep = ['id4', 'id2'];
data.forEach(o =>
o.items = Object
.keys(o.items)
.filter(k => Array.isArray(o.items[k]))
.reduce((r, k) => o
.items[k]
.reduce((s, p) => s.concat(keep.includes(p.id) ? p : []), r), []));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to bind foreign key kendo ui dropdownlist (with angular)

I am working with kendo UI and angular grid application. My grid is populated from JSON data (separate file) and I am use angular service:
My JSON data:
[
{ "Id": 1, "AccountNo": "10236", "PostingDate": "20.01.2015", "MaturityDate": "24.01.2015", "Description": "description1", "DocumentTypeId": 1 },
{ "Id": 2, "AccountNo": "10648", "PostingDate": "26.01.2015", "MaturityDate": "28.01.2015", "Description": "description2", "DocumentTypeId": 2 },
{ "Id": 3, "AccountNo": "10700", "PostingDate": "22.01.2015", "MaturityDate": "25.01.2015", "Description": "description3", "DocumentTypeId": 3 },
{ "Id": 4, "AccountNo": "10810", "PostingDate": "24.01.2015", "MaturityDate": "27.01.2015", "Description": "description4", "DocumentTypeId": 2 },
{ "Id": 5, "AccountNo": "10101", "PostingDate": "29.01.2015", "MaturityDate": "30.01.2015", "Description": "description5", "DocumentTypeId": 4 },
{ "Id": 6, "AccountNo": "10364", "PostingDate": "25.01.2015", "MaturityDate": "31.01.2015", "Description": "description6", "DocumentTypeId": 6 }
]
My Angular service:
angular.module("app").factory('myService', function ($http) {
return {
getAll: function (onSuccess, onError) {
return $http.get('/Scripts/app/data/json/master/masterGridData.js').success(function (data, status, headers, config) {
onSuccess(data);
}).error(function (data, status, headers, config) {
onError(data);
});
},
getDocumentTypes: function (onSuccess, onError) {
return $http.get('/Scripts/app/data/json/documentType.js').success(function (data, status, headers, config) {
onSuccess(data);
}).error(function (data, status, headers, config) {
onError(data);
});
}
}
});
This is my controller:
var app = angular.module("app", ["kendo.directives"]).controller("myController", function ($scope, myService) {
$scope.tabStrip = null;
$scope.$watch('tabStrip', function () {
$scope.tabStrip.select(0);
});
$scope.masterDataSource = new kendo.data.DataSource({
transport: {
read: function (options) {
url = "/Scripts/app/data/json/master/masterGridData.js",
myService.getAll(function (data) {
options.success(data);
}).error(function (data) {
options.error(data);
})
}
},
schema: {
model: {
id: "Id",
fields: {
Id: { type: "number" },
AccountNo: { type: "string" },
PostingDate: { type: "string" },
MaturityDate: { type: "string" },
Description: { type: "string" },
DocumentTypeId: { type: "number" }
}
}
},
pageSize: 16
});
$scope.gridMaster = {
columns: [
{ field: "Id", hidden: true },
{ field: "AccountNo", title: "Account No", width: "77px", template: '<div style="text-align:left;">#= kendo.toString(AccountNo) #</div>' },
{ field: "PostingDate", title: "Posting Date", width: "70px" },
{ field: "MaturityDate", title: "Maturity Date" width: "70px" },
{ field: "Description", title: "Description", width: "170px" },
{ field: "DocumentTypeId", hidden: true }
],
dataSource: $scope.masterDataSource,
selectable: true,
filterable: true,
scrollable: true,
pageable: {
pageSize: 16,
//refresh: true,
pageSizes: ["50", "100", "200", "All"]
},
toolbar: [{
name: "create"
}],
change: function () {
var dataItem = this.dataItem(this.select());
$scope.isRowSelected = true;
$scope.id = dataItem.Id;
$scope.accountNumber = dataItem.AccountNo;
$scope.postingDate = dataItem.PostingDate;
$scope.description = dataItem.Description;
$scope.maturityDate = dataItem.MaturityDate;
$scope.documentTypeId = dataItem.DocumentTypeId;
}
};
$scope.documentType = {
dataSource: {
transport: {
read: function (options) {
url = "/Scripts/app/data/json/documentType.js",
myService.getDocumentTypes(function (data) {
options.success(data);
}).error(function (data) {
options.error(data);
});
}
},
schema: {
model: {
id: "Id",
fields: {
Id: { type: "number" },
Name: { type: "string" }
}
}
}
},
dataTextField: "Name",
dataValueField: "Id"
}
});
This is my JSON which contain data for documentType:
[
{ "Id": 1, "Name": "Document 1" },
{ "Id": 2, "Name": "Document 2" },
{ "Id": 3, "Name": "Document 3" },
{ "Id": 4, "Name": "Document 4" },
{ "Id": 5, "Name": "Document 5" },
{ "Id": 6, "Name": "Document 6" }
]
And this is my HTML:
<html>
<head>
<!-- css and javaScript files -->
</head>
<body ng-app="app" ng-controller="myController">
<div class="divH3Style">
<h3 class="h3LabelForm">Grid Master</h3>
</div>
<div id="tabstrip" class="k-tabstrip-wrapper" data-kendo-tab-strip="tabStrip">
<ul>
<li>Overview</li>
<li>Update</li>
</ul>
<div id="tabstrip-1">
<div id="gridMaster" kendo-grid k-options="gridMaster" k-data-source="masterDataSource">
</div>
</div>
<div id="tabstrip-2" style="overflow: hidden">
<div id="tabStrip2Half1">
<div class="divHeightStyle">
<label for="accountNumber" class="labelTextSize">Account Number:</label>
<input id="accountNumber" type="number" class="k-textboxField" name="accountNumber" ng-model="accountNumber" placeholder="Account Number" />
</div>
<div class="datepickerStyle">
<label for="postingDate" class="labelTextSize">Posting Date:</label>
<input id="postingDate" class="k-datetimepickerMaster" name="postingDate" ng-model="postingDate" />
</div>
<div class="divHeightStyle">
<label for="desccription" class="labelTextSize">Description:</label>
<input id="desccription" type="text" class="k-textboxField" name="description" placeholder="Description" ng-model="description" />
</div>
<div class="datepickerStyle">
<label for="maturityDate" class="labelTextSize">Maturity Date:</label>
<input id="maturityDate" class="k-datetimepickerMaster" name="maturityDate" ng-model="maturityDate" />
</div>
</div>
<div id="tabStrip2Half2">
<div class="divHeightStyle">
<label for="documentType" class="labelTextSize">Document Type:</label>
<select kendo-drop-down-list
class="k-dropdownField" k-options="documentType"
ng-model="documentTypeId" ng-bind="documentTypeId"></select>
</div>
<div>
<button type="button" id="saveDataMasterGrid" class="k-button buttonSaveCancel" onclick="saveDataMasterGrid()">Save</button>
<button type="button" id="cancelDataMasterGrid" class="k-button buttonSaveCancel" onclick="cancelButtonMasterGrid()">Cancel</button>
</div>
</div>
</div>
</div>
</body>
</html>
In HTML I have dropdownlist which contain data for documentType and my dropdownlist is populated with JSON data. But, problem is in binding. When I select some grid row dropdownlist always display first item. My grid datasource contain foreign key value (documentTypeId) and this value should match with Id value from documentType JSON file, ie $scope.documentType property dataValueFiled value. How can bind this dropdownlist? Pls help..
For solve that problem I use hardCoded variable:
$scope.documentTypeDS = [
{ "value": 1, "text": "doc 1" },
{ "value": 2, "text": "doc 2" },
{ "value": 3, "text": "doc 3" },
{ "value": 4, "text": "doc 4" },
{ "value": 5, "text": "doc 5" },
{ "value": 6, "text": "doc 6" }
];
And modified definition for my gridMaster. In gridMaster column property I insert:
{ field: "DocumentTypeId", hidden: true, values: $scope.documentTypeDS },
And, In HTML i modified code lines, from this:
<select kendo-drop-down-list
class="k-dropdownField" k-options="documentType"
ng-model="documentTypeId" ng-bind="documentTypeId"></select>
to this:
<input kendo-drop-down-list k-data-text-field="'text'" k-data-value-field="'value'" data-bind="value:documentTypeId"
class="k-dropdownField" k-data-source="documentType" ng-readonly="isReadonly" ng-model="documentTypeId" />
I suppose that there is a better solution of this, because I use hardCoded part of code for define $scope.documentTypeDS.

Categories