Why vuejs array shows empty even if it not? - javascript

I have a list of checkbox which is dynamic.
Whenever I click on the checkbox, it is binded to the data array. The index is provided as the top company name. But the array shows empty when I log the array. But if I iterate through it and log again, it shows the values.
In JS we cannot set the array index directly. Is that the problem?
Code:
new Vue({
el: '#app',
data: {
topCompanies: [{
"doc_count": 221,
"key": "a"
},
{
"doc_count": 175,
"key": "b"
},
{
"doc_count": 149,
"key": "c"
},
{
"doc_count": 126,
"key": "d"
},
{
"doc_count": 116,
"key": "e"
},
{
"doc_count": 115,
"key": "f"
},
{
"doc_count": 94,
"key": "g"
},
{
"doc_count": 89,
"key": "h"
},
{
"doc_count": 75,
"key": "h"
},
{
"doc_count": 72,
"key": "i"
}
],
collapse1: false,
checked_company: []
},
methods: {
getResultsByCompany(result) {
console.log(this.checked_company)
temp = []
for (i in this.checked_company) {
console.log(i)
}
}
}
});
<div id="app">
<div id="sidebar-wrapper">
<button class="collapsible" #click="collapse1=!collapse1">Top Companies</button>
<div v-if="collapse1" class="content" v-bind:style="{'display': 'block'}">
<div class="list-group" v-for = "(result,index) in topCompanies" :key="result.id">
<label class="container check-an" :id="index" #change = "getResultsByCompany(result.key)">{{ result.key}}({{result.doc_count }})
<input type="checkbox" v-model="checked_company[result.key]">
<span class="checkmark"></span>
</label>
</div>
js fiddle: https://jsfiddle.net/Lbkx5zdt/

You declare checked_company as an array, but you treat it as an object checked_company[result.key]
If you want to save all checked company key in an array, then your checkbox code should be
<input type="checkbox" :value="result.key" v-model="checked_company">
Demo: https://jsfiddle.net/ittus/9jya1gas/

I see you seem missing several div tags
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<div id="sidebar-wrapper">
<button class="collapsible" #click="collapse1=!collapse1">Top Companies</button>
<div v-if="collapse1" class="content" v-bind:style="{'display': 'block'}">
<div class="list-group" v-for = "(result,index) in topCompanies" :key="result.id">
<label class="container check-an" :id="index" #change = "getResultsByCompany(result.key)">{{ result.key}}({{result.doc_count }})
<input type="checkbox" v-model="checked_company[result.key]">
<span class="checkmark"></span>
</label>
</div>
</div>
</div>
</div>
It make vuejs don't know el scope

I'm not really sure this will be the issue but have you checked that 'this' refers to the correct object? Potentially you could assign a variable to new Vue and reference the object globally. Hope it helps.

Related

v-bind in nested component for radio input is breaking

The problem is I cannot click nested radio button but able to click top level radio buttons.
I have this component imported in parent view:
<app-group-radio-item
v-for="groupsNested in groupsDataNested"
:key="groupsNested.group_id"
:groups="groupsNested"
:groupInputtedData="groupInputtedData">
</app-group-radio-item>
<script>
import AppGroupRadioItem from "./GroupRadioItem";
export default {
name: 'addGroup',
components: {AppGroupRadioItem},
props: {
groupsDataNested: Array,
},
data(){
return {
groupInputtedData: {
group_name: '',
group_type_id: '',
group_parent_id: ''
}
}
}
}
</script>
The Nested component that I am importing:
<template>
<div class="list-group list-group-flush">
<div class="list-group-item">
<div class="form-group">
<label class="custom-control custom-radio">
<input type="radio" class="custom-control-input"
:value="groups.group_id"
v-model="groupInputtedData.group_parent_id">
<span class="custom-control-indicator"></span>
<span class="custom-control-description">{{groups.group_name}}</span>
</label>
</div>
</div>
<div class="collapse nested-items"
:id="'collapseExample' + groups.group_id + 'radio'"
v-if="hasChildren">
<app-group-radio-item
v-for="groupsNested in groups.groups"
:key="groupsNested.group_id"
:groups="groupsNested"
:groupInputtedData="groupInputtedData">
</app-group-radio-item>
</div>
</div>
</template>
<script>
export default {
name: 'appGroupRadioItem',
data: function () {},
props: {
groups: Object,
groupInputtedData: Object
}
}
</script>
Thanks in advance.
Found Solution my own question:
First I had used select but later I thought of using radio, but just for debugging purpose I did not remove select and never though that will cause issue as the radio first level buttons were working fine.
Here is the select code that was causing the problem:
<div class="form-group">
<label for="inputAddGroupParent">Parent</label>
<select class="form-control" id="inputAddGroupParent" v-model="groupInputtedData.group_parent_id">
<option :value="0">None</option>
<option v-for="groupsNested in groupsDataNested" :value="groupsNested.group_id">{{groupsNested.group_name}} {{groupsNested.group_id}}</option>
</select>
</div>
While debugging I had to create minimal working example, so that I can reproduce the issue, so that someone can help me here in stack overflow but ended have a working code :) So, here is it, feel free to use if someone need it.
let data = [ { "group_id": 36, "group_parent_id": null, "group_name": "Fresno Bee", "group_type_id": 1, "groups": [ { "group_id": 38, "group_parent_id": 36, "group_name": "Test", "group_type_id": 3, "groups": [] } ] }, { "group_id": 21, "group_parent_id": null, "group_name": "Miami Herald", "group_type_id": 1, "groups": [ { "group_id": 28, "group_parent_id": 21, "group_name": "Business", "group_type_id": 3, "groups": [] }, { "group_id": 29, "group_parent_id": 21, "group_name": "Sports", "group_type_id": 3, "groups": [ { "group_id": 34, "group_parent_id": 29, "group_name": "Football", "group_type_id": 3, "groups": [] }, { "group_id": 35, "group_parent_id": 29, "group_name": "Tennis", "group_type_id": 3, "groups": [] } ] } ] }, { "group_id": 23, "group_parent_id": 20, "group_name": "Sacramento Bee", "group_type_id": 1, "groups": [ { "group_id": 30, "group_parent_id": 23, "group_name": "Money", "group_type_id": 3, "groups": [] }, { "group_id": 25, "group_parent_id": 23, "group_name": "Sports", "group_type_id": 3, "groups": [] } ] } ]
Vue.component('AppGroupRadioItem', {
props: {
groups: Object,
inputtedData: Object
},
template: '#group-template'
});
new Vue({
el: '#app',
data() {
return {
groupsDataNested: data,
groupInputtedData: {
group_name: '',
group_type_id: '',
group_parent_id: ''
}
}
}
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<!--<script src="//unpkg.com/vue#2.4.1"></script>--> <!-- works in 2.4.1 as well -->
<div id="app">
<div class="container">
<div class="row">
<div class="col-6">
<div class="card rounded-0 border-top-0 border-bottom-0">
<app-group-radio-item
v-for="groupsNested in groupsDataNested"
:key="groupsNested.group_id"
:groups="groupsNested"
:inputted-data="groupInputtedData">
</app-group-radio-item>
</div>
</div>
<div class="col-6">
<h3>groupInputtedData: {{groupInputtedData.group_parent_id}}</h3>
</div>
</div>
</div>
</div>
<script type="text/x-template" id="group-template">
<div class="list-group list-group-flush">
<div class="list-group-item">
<div class="form-group">
<label class="custom-control custom-radio">
<input type="radio" class="custom-control-input"
:value="groups.group_id"
v-model="inputtedData.group_parent_id">
<span class="custom-control-indicator"></span>
<span class="custom-control-description">{{groups.group_name}}</span>
</label>
</div>
</div>
<div class="nested-items">
<app-group-radio-item
v-for="groupsNested in groups.groups"
:key="groupsNested.group_id"
:groups="groupsNested"
:inputted-data="inputtedData"
style="padding-left: 40px">
</app-group-radio-item>
</div>
</div>
</script>

V-client-table filterbycolumn how do I get the filter to work for some but not all columns?

this is a question about vue and its v-table, specifically its v-client-table
This example has a filter on name pets and birthdays but not on age, edit or delete. https://jsfiddle.net/f5h8xwgn/299/
I need something similar but I'm unable to reproduce the affect in my project. I have 3 columns: name, active, and edit - edit is just a bunch of buttons - I don't need to sort or filter buttons.
this is my code code for the table:
<v-client-table :data="filteredList"
:columns="['name', 'active', 'edit']" :options="options"
>
<template slot="name" scope="props">
<div v-if="props.row.editing">
<textbox v-model="editName"></textbox>
</div>
<div v-else>{{ props.row.name }}</div>
</template>
<template slot="active" scope="props">
<div v-if="props.row.editing">
<select class="form-control" v-model="editActive">
<option v-bind:value="1">Active</option>
<option v-bind:value="0">Inactive</option>
</select>
</div>
<div v-else>
<div v-if="props.row.active">Active</div>
<div v-else>Inactive</div>
</div>
</template>
<template slot="edit" scope="props">
<div class="text-right">
<button type = "button"
#click="editFabricator(props.row)"
class="btn btn-primary">
<div v-if="props.row.editing">Cancel</div>
<div v-else>Edit</div>
</button>
<button v-if="props.row.editing"
type = "button"
#click="saveEdit(props.row.id)" class="btn btn-primary">
Save
</button>
</div>
</template>
</v-client-table>
this is my options
options: {
filterByColumn: true,
headers: {
name: 'Name',
active: 'Active',
edit: 'Edit',
},
listColumns: {
active: [{
id: '0',
text: 'Inactive'
}, {
id: '1',
text: 'Active'
}]
},
}
in the example on jsfiddle edit isn't listed in the :columns list when the table is declared but it still shows up in the table. if I remove edit from the :columns list it removes the edit column from the table and no matter what I do I can't get it to show up. if I put edit in the :columns list then the column is there but it has a filter. which I don't want.
this is for a laravel project. not sure if that makes a difference.
Under Options add the columns you want to filter by using the
filterable option.
{
"options": {
"filterByColumn": true,
"filterable": [
"name",
"active"
],
"headers": {
"name": "Name",
"active": "Active",
"edit": "Edit"
},
"listColumns": {
"active": [
{
"id": "0",
"text": "Inactive"
},
{
"id": "1",
"text": "Active"
}
]
}
}
}
https://matanya.gitbook.io/vue-tables-2/options-api

AngularJS populate a <select> field based on input from previous <select> field

I have 2 dropdown menus that are dependent on one another. The first one works perfectly, but I want the second dropdown to populate based on the choice in the first menu. I realize that similar questions have been asked before, but my data seems to be in a different format. Here is my code:
<body ng-app="patientSim" ng-controller="patientCtrl">
<button style="width:20%;" ng-click="addChar()">Add Characteristic</button>
<div class="row">
<div class="col-md-3"><select ng-model="selectedCategory" ng-options="x.cat as (x.cat | underFilter) for x in (enumChars | duplicateFilter)"></select></div>
<div class="col-md-3"><select ng-model="selectedName" ng-options="x.enumName as (x.enumName | underFilter) for x in enumChars"></select></div>
<div class="col-md-3"><button ng-click="eqWeight()">Equalize Weights</button></div>
<div class="col-md-3"><button ng-click="reset()">Reset</button></div>
</div>
And here are 2 sections of the JSON:
{
"enumID": 1,
"enumName": "Gender",
"isTree": false,
"enumAlloc": 10,
"enumVals": [
"Unknown",
"Male",
"Female",
"Transgender"
],
"enumText": null,
"cat": "Demographics"
},
{
"enumID": 2,
"enumName": "Race",
"isTree": false,
"enumAlloc": 15,
"enumVals": [
"Unknown",
"American Indian/Alaska Native",
"Asian",
"Black",
"Native Hawaiian/Other Pacific Islander",
"White/Caucasian",
"Other"
],
"enumText": null,
"cat": "Demographics"
},
The first dropdown is populated with "Demographics" and "Diseases and Injuries", both under the "cat" name. The entire file contains 5 "Demographics" sections and 1 "Diseases and Injures" section. All 6 sections are stored in a scope value called enumChars, which I used in ng-options. There are over 45,000 values for some sections, so I didn't want to post them here. My goal is for the second dropdown to populate with the "enumName" corresponding to the "cat". So for example, if I select "Demographics" in the first dropdown, the second dropdown will populate with "Gender", "Race", and the other enumName values in the other sections also containing "cat": "Demographics". How would I go about doing this? Thanks!!
If I understood your question well you want to populate with the enumVals the 2nd <select> based on the value selected in the 1st. <select>.
Then, if I'm correct, you can do the following:
(function() {
"use strict";
angular.module('app', [])
.controller('mainCtrl', function($scope) {
$scope.enumChars = [
{
"enumID":1,
"enumName":"Gender",
"isTree":false,
"enumAlloc":10,
"enumVals":[
"Unknown",
"Male",
"Female",
"Transgender"
],
"enumText":null,
"cat":"Any category"
},
{
"enumID":2,
"enumName":"Race",
"isTree":false,
"enumAlloc":15,
"enumVals":[
"Unknown",
"American Indian/Alaska Native",
"Asian",
"Black",
"Native Hawaiian/Other Pacific Islander",
"White/Caucasian",
"Other"
],
"enumText":null,
"cat":"Demographics"
}
];
});
})();
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-messages/1.5.7/angular-messages.min.js"></script>
</head>
<body ng-controller="mainCtrl">
<button style="width:20%;" ng-click="addChar()">Add Characteristic</button>
<div class="row">
<div class="col-md-3">
<select ng-model="selectedCategory" ng-options="obj as obj.cat for obj in enumChars"></select>
</div>
<div class="col-md-3" ng-if="selectedCategory">
<select ng-model="selectedName" ng-options="enum for enum in selectedCategory.enumVals"></select>
</div>
<div class="col-md-3">
<button ng-click="eqWeight()">Equalize Weights</button>
</div>
<div class="col-md-3">
<button ng-click="reset()">Reset</button>
</div>
</div>
</body>
</html>

How to display a set using ng-repeat in angularjs

I have this json set that needs to be displayed (in columns):
{
"2": [
{
"$id": "1",
"serverId": 1622,
"innCode": "PLOIKJ7",
"propertyName": "Property 1",
},
{
"$id": "2",
"serverId": 1622,
"innCode": "BHGTRWA",
"propertyName": "Property 2",
}
],
"3": [
{
"$id": "3",
"serverId": 1623,
"innCode": "TGHRE#W",
"propertyName": "Property 3",
}
]
}
I can't think of a way to "loop" through it using ng-repeat. I have the following template defined as a starter:
<div ng-repeat="s in sets">
<div class="panel panel-info">
<div class="panel-heading"><span><bold>Server: {{s.serverNum}}</bold></span></div>
<div class="panel-body">
<div>
<input type="checkbox" value="all#" ng-click="doNothing($event)"/>Select All
</div>
<div class="divider"> </div>
<div ng-repeat="p in s.properties">
<label class="margin-right12">
<input type="checkbox" name="property_{{p.innCode}}"
value="{{p.innCode}}" ng-click="doNothing($event)"/> <small>{{innCode}} - {{p.propertyName}}</small>
</label>
</div>
</div>
</div>
</div>
Thanks!
You can do like this
Inside the controller
$scope.data = {
"2": [
{
"$id": "1",
"serverId": 1622,
"innCode": "PLOIKJ7",
"propertyName": "Property 1",
},
{
"$id": "2",
"serverId": 1622,
"innCode": "BHGTRWA",
"propertyName": "Property 2",
}
],
"3": [
{
"$id": "3",
"serverId": 1623,
"innCode": "TGHRE#W",
"propertyName": "Property 3",
}
]
};
Inside the template
<div ng-controller="yourCntroName">
<div ng-repeat="(key, val) in data">// By this line you will get all keys of your set. '2' and '3' in your case
<div ng-repeat="obj in val"> // val will give you value of key(first time '2' and second time '3' in your case) that is an array so again use repeat.
{{'$id = '+obj.$id+' ,'}}{{'serverId = '+obj.serverId}}
</div>
</div>
</div>
The documentation for the built-in ng-repeat directive is available here.
Based on that documentation, the applicable expression for your use case should be ng-repeat="(key, value) in expression". expression should be substituted with set in your code.
Eventually you should arrive at something like this:
<div ng-repeat="(count, servers) in sets">
<div class="panel panel-info">
<div class="panel-heading">
<span><bold>Server: {{count}}</bold></span>
</div>
<div class="panel-body">
<div>
<input type="checkbox" value="all#" ng-click="doNothing($event)" />Select All
</div>
<div class="divider"> </div>
<div ng-repeat="server in servers">
<label class="margin-right12">
<input type="checkbox" name="property_{{server.innCode}}" value="{{server.innCode}}" ng-click="doNothing($event)" /> <small>{{server.innCode}} - {{server.propertyName}}</small>
</label>
</div>
</div>
</div>
</div>
Your markup could use a lot of improvement, but one thing at a time - I suggest you read the doc.

How to make knockout with nested object which might not be array always

I had a nested JSON object in this form
var termValues=[
{
clause_title:"One",
clause_id:"One",
CM_terms: [
{ termName: 'CompanyName', type:"text", termValue:"CompanyName1", termId:'1' },
{ termName: 'Contract termValue', type:"number", termValue:"1234",termId:'2' },
{ termName: 'Contract End', type:"date", termValue:"2012-02-02", termId:'3' }
]
},
{
clause_title:"Two",
clause_id:"Two",
CM_terms: [
{ termName: 'CompanyName', type:"text", termValue:"CompanyName2", termId:'4' },
{ termName: 'Contract termValue', type:"number", termValue:"5678",termId:'5' },
{ termName: 'Contract End', type:"date", termValue:"2011-02-02", termId:'6' }
]
}
];
I applied binding in this form
function TestModel (termValues)
{
var self=this;
self.Clauses=ko.observableArray(termValues)
}
ko.applyBindings(new TestModel(termValues),$("#ctrTerms1")[0]);
HTML code:
<div data-bind="foreach: Clauses" id="ctrTerms1">
<div class="panel">
<div class="control-bar panel-heading">
<h4 class="panel-title" style="overflow:auto">
<a class="col-md-12 clref">
<span class="clause-title" title="Click to edit" data-bind="text: Clauses.clause_title"></span>
</a>
</h4>
</div>
<div>
<div class="panel-body">
<form class="form-horizontal" role="form" data-bind="foreach: CM_terms">
<div class="form-group" >
<label class="col-md-2 control-label" data-bind="text: termName">Title</label>
<div class="col-md-9">
<input type="text" class="form-control cttermValue" id="clauseTitle" data-bind="value: termValue">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
Now the issue is if I have more than 1 term I CM_terms will be in the form of an Array so for-each of CM_terms will work, But if I have only 1 CM_terms (Single object), Knock out is not able to bind as CM_term will not be array.
var termValues=[
{
clause_title:"One",
clause_id:"One",
CM_terms:
{ termName: 'CompanyName', type:"text", termValue:"companyName1", termId:'1' }
];
How Can I make 'CM_term' values to convert to Array if it is a Single Object.
As of now I am Iterating termValues and making CM_terms to Array if its not an Array and then applying Bindings.
Is there any other way.
If you have single object then push it into array. In your case CM_terms always should be an array, no matter whether it has single object or multiple objects.
var termValues=[
{
clause_title: "One",
clause_id: "One",
CM_terms: [
{
termName: 'CompanyName',
type: "text",
termValue: "Cordys",
termId: '1'
}
]
];
Fiddle Demo
This is how we can solve the problem. Got a clue from one of the stack-over flow post(will post if found gain)
We can use data-bind="foreach:{data:$data.CM_Terms}". We get desired result even if CM_Terms is not an Array
<div class="panel-body" data-bind="foreach: {data:$data.CM_terms}">
JSFiddle

Categories

Resources