Check/Uncheck all checkbox in group Vue.js - javascript

I have an Array of checkbox which already divided in to groups and I need to check all child checkbox if parent is checked and uncheck if parent is uncheck and then update all their state in Array. This wayyy over my head since I'm realy new to Vue.
I setup a Codepen here, and I can't change Array's structure since it's a JSON response from server.
Js
let tree = [
{
"text": "AccountController",
"id": 1,
"state": {
"opened": false,
"selected": true,
"disabled": false
},
"children": [
{
"text": "Index",
"id": 2,
"state": {
"opened": false,
"selected": true,
"disabled": false
},
"children": null
},
{
"text": "Login",
"id": 3,
"state": {
"opened": false,
"selected": true,
"disabled": false
},
"children": null
},
...
]
},
{
"text": "BaseController",
"id": 19,
"state": {
"opened": false,
"selected": true,
"disabled": false
},
"children": [
{
"text": "GetErrorListFromModelState",
"id": 20,
"state": {
"opened": false,
"selected": true,
"disabled": false
},
"children": null
},
{
"text": "GetErrorFromModelState",
"id": 21,
"state": {
"opened": false,
"selected": true,
"disabled": false
},
"children": null
},
...
]
}
]
let app = new Vue({
el : '#clone',
data : {
items : tree,
},
methods : {
submitForm() {
console.log(tree);
}
}
});
Html
<div id="clone">
<button #click="submitForm">click</button>
<div class="dd">
<ol class="dd-list">
<li v-for="(item, index) in items"
v-bind:class="[item.state.opened ? 'dd-item open' : 'dd-item']">
<div class="dd-handle"
#click="item.state.opened = !item.state.opened">
<input type="checkbox"
:disabled="item.state.disabled"
:name="item.text"
:checked="item.state.selected"
#click="item.state.selected = !item.state.selected">
<label :for="item.text">{{item.text}}</label>
</div>
<ol v-if="item.children.length != 0" class="dd-list">
<li v-for="(children, index) in item.children"
:data-id="children.id" class="dd-item">
<div class="dd-handle">
<input type="checkbox"
:name="children.text"
:checked="children.state.selected"
:disabled="children.state.disabled"
#click="children.state.selected = !children.state.selected">
<label :for="children.text">{{children.text}}</label>
</div>
</li>
</ol>
</li>
</ol>
</div>
</div>
Can someone enlighten me please. Thank in advance!

In the template,
<input type="checkbox"
:disabled="item.state.disabled"
:name="item.text"
:checked="item.state.selected"
#click="item.state.selected = !item.state.selected"
#change="onChange(item, item.state.selected)">
And add the method,
methods : {
submitForm() {
console.log(tree);
},
onChange(item, state){
for(let child of item.children){
child.state.selected = state
}
}
}
Updated pen.

Related

How can I loop inside a loop and sort results from a JSON object via AJAX call?

I'm currently working on creating a dynamic carousel that is built by using data from a JSON object with the following basic structure:
[{
"category": {
"href": "somecategory/categoryid",
"id": "somecategory/categoryid",
"ID": "CATEGORYID01",
"name": "Orders",
"locale": "gb",
"position": 2,
"outdated": false,
"slug": "category-1",
"icon": ""
},
"articles": [{
"href": "somearticle/articleid",
"id": "somearticle/articleid",
"ID": "ARTICLEID01",
"position": 1,
"voteUpCount": 94,
"voteDownCount": 1105,
"categories": [{
"position": 1,
"category": "CATEGORYID01"
}],
"keywords": [
"Missing-order"
],
"title": "Article 1 title",
"body": "<p>article body</p>",
"locale": "gb",
"outdated": false,
"slug": "article-1",
"views": 0,
"labelName": [
""
]
},
{
"href": "somearticle/articleid",
"id": "somearticle/articleid",
"ID": "ARTICLEID02",
"position": 2,
"voteUpCount": 94,
"voteDownCount": 1105,
"categories": [{
"position": 1,
"category": "CATEGORYID01"
}],
"keywords": [
"Missing-order"
],
"title": "Article 2 title",
"body": "<p>article body</p>",
"locale": "gb",
"outdated": false,
"slug": "article-2",
"views": 0,
"labelName": [
""
]
},
{
"href": "somearticle/articleid",
"id": "somearticle/articleid",
"ID": "ARTICLEID03",
"position": 3,
"voteUpCount": 94,
"voteDownCount": 1105,
"categories": [{
"position": 1,
"category": "CATEGORYID01"
}],
"keywords": [
"Missing-order"
],
"title": "Article 3 title",
"body": "<p>article body</p>",
"locale": "gb",
"outdated": false,
"slug": "article-3",
"views": 0,
"labelName": [
""
]
}
]
}]
The above structure repeats depending on how many categories there are, so you have CATEGORIES with the ARTICLES that belong to that category right below it (also identified by the category ID inside the articles data), so for example, if you have 2 categories the JSON structure would be:
[{
"category":{},
"articles":[{several articles here}],
"category":{},
"articles":[{several articles here}]
}]
I have already managed to create the dynamic slides for the carousel, creating one slide per each category available within the JSON, but now I have to populate each category slide with all the articles belonging to that particular category. The code I'm using to create the slides is the following:
function getfaqsCarousel(){
faqsCarousel().then((data) => { // THE AJAX CALL IS ON ITS OWN SEPARATE FUNCTION ( faqsCarousel() )
var article_data = '';
$.each(data, function(key, value){
var category = value.category.slug;
var catname = value.category.name;
var position = value.category.position;
var catid = value.category.ID;
var articleid = value.articles.categories.category;
if (category != 'faqs-home') {
article_data += `<div>
<div class="cc-box">
<div class="cc-hoverbox"> <span> <img alt="faqIcon" src="`+ value.category.icon +`" /> </span>
<h3>`+ catname +`</h3>
<ul class="feature-list">
<li>articles here</li>
</ul>
</div>
<a class="viewBtn" href="javascript:void(0)" data-category="`+ catid +`" data-slug="`+ category +`">See All</a> </div>
</div>`;
}
});
$('.faq-slider').html(article_data);
$('.faq-slider').slick({
lazyLoad: "progressive",
slidesToShow: 3,
responsive: [{
breakpoint: 768,
settings: {
arrows: true,
centerMode: !0,
centerPadding: "40px",
slidesToShow: 1
}
}]
})
});
}
getfaqsCarousel();
Now, inside that $.each loop, I need to loop through all the articles for each category to replace the part of the code <li>articles here</li>
So my question is: How can I loop through all the articles inside the already existing categories loop and at the same time, SORT the results by the position property available inside each article?
Thanks for your time beforehand.
function getfaqsCarousel() {
faqsCarousel().then((data) => { // THE AJAX CALL IS ON ITS OWN SEPARATE FUNCTION ( faqsCarousel() )
var article_data = '';
$.each(data, function (key, value) {
//...more code on top
var articles = value.articles
var desiredArticleStructure = ""
//here sort and loop through all the articles
var sortedArticles = articles.sort(function (a, b) {
return a.position - b.position
})
sortedArticles.map(article => {
$('.title').innerText = article.title
$('.title body').innerHtml = article.body
//...your structure goes on
desiredArticleStructure += `
<div class='title'>
<div class="body"></div>
</div>
`
})
if (category != 'faqs-home') {
article_data += `<div>
<div class="cc-box">
<div class="cc-hoverbox"> <span> <img alt="faqIcon" src="`+ value.category.icon + `" /> </span>
<h3>`+ catname + `</h3>
<ul class="feature-list">
<li>articles here</li>
</ul>
</div>
<a class="viewBtn" href="javascript:void(0)" data-category="`+ catid + `" data-slug="` + category + `">See All</a> </div>
</div>`;
}
$('.feature-list').innerHtml = desiredArticleStructure
});
});
}
getfaqsCarousel();

Problem setting indeterminate value of parent checkbox in group

I have a JSON file with hierarchical data:
[
{
"id": 0,
"label": "Gap Inc.",
"value": "Gap Inc",
"checked": false,
"children": [
{
"id": 0,
"label": "Banana Republic",
"value": "Banana Republic",
"checked": false
},
{
"id": 1,
"label": "Gap",
"value": "Gap ",
"checked": false
},
{
"id": 2,
"label": "Hill City",
"value": "Hill City",
"checked": false
},
{
"id": 3,
"label": "Old Navy",
"value": "Old Navy",
"checked": false
}
]
},
{
"id": 1,
"label": "Home Depot",
"value": "Home Depot",
"checked": false,
"children": []
},
{
"id": 2,
"label": "TJX",
"value": "TJX Companies",
"checked": false,
"children": [
{
"id": 0,
"label": "TJ Maxx",
"value": "TJ Maxx ",
"checked": false
},
{
"id": 1,
"label": "Marshalls",
"value": "Marshalls",
"checked": false
},
{
"id": 2,
"label": "Home Goods",
"value": "Home Goods",
"checked": false
}
]
}
]
I am using it to create a set of nested HTML lists with checkboxes:
<ul class="list-unstyled">
<li *ngFor="let parent of accountList; let q = index">
<div class="form-check">
<input id="parent-{{q}}"
class="form-check-input"
type="checkbox"
[(ngModel)]="parent.checked"
(click)="selectChildren(parent, $event)"
[indeterminate]="selectedChildren.length">
<label for="parent-item" class="form-check-label">
{{parent.label}}
</label>
</div>
<ul class="list-unstyled pl-4">
<li *ngFor="let child of parent.children; let i = index;">
<div class="form-check">
<input id="child-{{i}}"
class="form-check-input"
type="checkbox"
[(ngModel)]="child.checked"
(click)="selectChild(child, $event)">
<label for="child-{{i}}" class="form-check-label">
{{child.label}}
</label>
</div>
</li>
</ul>
</li>
</ul>
What's supposed to happen
If you click a parent checkbox, it checks all the children.
If you click only one child, its parent is set to indeterminate.
What DOES happen
If you click a parent checkbox, it checks all the children.
If you click only one child, ALL parents are set to indeterminate.
I assume I screwed up something somewhere. I think I have mapped the indeterminate attribute to the length of any selected children (here selectedChildren instead of only the children of the given parent. Not sure how to fix that...
Here is the typescript:
selectedChildren = [];
selectChildren = function(data, event) {
const parentChecked = !data.checked;
data.children.forEach((child, key2) => {
child.checked = parentChecked;
});
};
selectChild = (data, event) => {
if (this.selectedChildren.indexOf(data.id) === -1) {
this.selectedChildren.push(data.id);
data.checked = true;
} else {
this.selectedChildren.splice(this.selectedChildren.indexOf(data.id), 1);
data.checked = false;
}
};

populate multiple dropdown select boxes from JSON data in angular

Firstly, after numerous searches this question does not answer my issue.
I am using AngularJS Dropdown Multiselect and wish to populate a number of dropdowns that are extracted from my JSON data. An example of this data is below:
{
"results": [
{
"title": "Difficulty",
"icon": "difficulty-icon",
"filters": [{
"name": "Easy",
"checked": false
}, {
"name": "Medium",
"checked": false
}, {
"name": "Hard",
"checked": false
}, {
"name": "Expert",
"checked": false
}]
},
{
"title": "Direction of Movement",
"icon": "direction-icon",
"filters": [{
"name": "Flexion",
"checked": false
}, {
"name": "Ulnar Deviation",
"checked": false
}, {
"name": "Radial Deviation",
"checked": false
}]
},
{
"title": "Exercise Aim",
"icon": "aim-icon",
"filters": [{
"name": "Power",
"checked": false
}, {
"name": "Strength",
"checked": false
}]
}, {
"title": "Muscle Group ",
"icon": "muscle-icon",
"filters": [{
"name": "Foot & Shin",
"checked": false
}]
},
{
"title": "Joint",
"icon": "joint-icon",
"filters": [{
"name": "Foot and Ankle",
"checked": false
}, {
"name": "Knee",
"checked": false
}]
}
]
}
When any of these items are selected I need to push the value to an array (the array is not specific to the dropdown it has come from therefore can share the same model).
I would like to run an ng-repeat that will create 5 dropdowns that are populated from the data above with the custom button text displaying the Title from my JSON data.
Is this possible? If not how can I run a function in my controller in order to seporate this data in order to expose each section of JSON data to the $scope
UPDATE
So far I have managed to get this: however unsure how I can get the Title property
<div ng-repeat="select in Filters">
<div ng-dropdown-multiselect="" options="Filters[$index].filters" selected-model="example1model" extra-settings="filterSettings"></div>
</div>
Here is a snippet with an example of MultiSelect dropdown in a ngRepeat loop:
var app = angular.module('myApp', ['angularjs-dropdown-multiselect']);
app.controller("appController", function($scope) {
$scope.filterSettings = {
displayProp: 'name',
idProp: 'name'
};
$scope.all_data = {
"results": [
{
"title": "Difficulty",
"icon": "difficulty-icon",
"filters": [{
"name": "Easy",
"checked": false
}, {
"name": "Medium",
"checked": false
}, {
"name": "Hard",
"checked": false
}, {
"name": "Expert",
"checked": false
}]
},
{
"title": "Direction of Movement",
"icon": "direction-icon",
"filters": [{
"name": "Flexion",
"checked": false
}, {
"name": "Ulnar Deviation",
"checked": false
}, {
"name": "Radial Deviation",
"checked": false
}]
},
{
"title": "Exercise Aim",
"icon": "aim-icon",
"filters": [{
"name": "Power",
"checked": false
}, {
"name": "Strength",
"checked": false
}]
}, {
"title": "Muscle Group ",
"icon": "muscle-icon",
"filters": [{
"name": "Foot & Shin",
"checked": false
}]
},
{
"title": "Joint",
"icon": "joint-icon",
"filters": [{
"name": "Foot and Ankle",
"checked": false
}, {
"name": "Knee",
"checked": false
}]
}
]
};
angular.forEach($scope.all_data.results, function(item, key) {
item.model = [];
});
});
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.3.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<script src="//rawgit.com/dotansimha/angularjs-dropdown-multiselect/master/src/angularjs-dropdown-multiselect.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="appController">
<div>
<div ng-repeat="mydata in all_data.results">
<div ng-dropdown-multiselect="" options="mydata.filters" selected-model="mydata.model" extra-settings="filterSettings"></div>
<pre>mydata.model = {{mydata.model | json}}
</pre>
</div>
</div>
</body>
</html>
The models which receive user input (selection) for each multiselect is added to data in the Angular.forEach loop.

Applying filter on parent if it has been applied on children AngularJS

I have a list with items and have applied filter on those items by value from text box. I want to get new filtered list with parent and its children if parent has at least one filtered item.If doesn't, that parent should not be displayed.
For an example: If I enter "3D" in the text box I don't want to get "Day parts" and "Week parts" listed below as they don't have children anymore after filtering.
<div ng-controller="Ctrl">
<input type="text" data-ng-model="inputValue.name"/>
<ul data-ng-repeat="condition in conditions">
<div data-ng-click="setHeadingStatus(condition)">
<div>
{{condition.name}}
</div>
<li ng-repeat="item in condition.items | filter:inputValue">
<div class="custom-typeahead-list-title">{{item.name}}</div>
<div class="custom-typeahead-list-desc">{{item.description}}</div>
</li>
</div>
</ul>
function Ctrl($scope , $filter){
$scope.countryCode = 1;
$scope.conditions = [
{
"id": 1,
"name": "Experiences",
"expanded": false,
"items": [
{
"id": 1,
"name": "3D"
},
{
"id": 2,
"name": "Imax"
},
{
"id": 3,
"name": "D-Box"
},
{
"id": 4,
"name": "THX"
}
]
},
{
"id": 2,
"name": "Day parts",
"expanded": false,
"items": [
{
"id": 1,
"name": "Early Bird"
},
{
"id": 2,
"name": "Matinee"
},
{
"id": 3,
"name": "Last Night"
}
]
},
{
"id": 3,
"name": "Week parts",
"expanded": false,
"items": [
{
"id": 1,
"name": "Monday"
},
{
"id": 2,
"name": "Wednesday"
},
{
"id": 3,
"name": "Weekend"
}
]
}
]
}
Here is the example of it
http://jsfiddle.net/KJ3Nx/48/
You can put an ng-show on the div that displays each block, and set the expression to the filtered length;
<div data-ng-show="(condition.items | filter:inputValue).length > 0" data-ng-click="setHeadingStatus(condition)">
Updated fiddle

Count items in array where expression is true

I´m an angular newbie
I have a directive with a template that looks something like this:
<div class="multiselect-styled">
<a href="javascript:void(0);" class="link" id="link-{{ model.ControlId }}">
<span class="options-selected" id="selected-options-{{ model.ControlId }}">TEXT</span>
<span class="select-arrows"></span>
</a>
</div>
My model contains an array called Options which contains n number of selectable options. Each option object has a boolean property; Selected. I would like to replace TEXT with a string saying n options selected. So, how do I get the number of selected options?
Of course, using a loop one would do something like this but is there some way I kind bind directly to n in this case (Find n with an expression)?
var n = 0;
angular.forEach(model.Options, function(option) {
if (option.Selected)
n++;
});
UPDATE 1
Options look like this:
"Options": [
{
"Id": "ApprovedAndClosed",
"Value": "ApprovedAndClosed",
"Text": "ApprovedAndClosed",
"Selected": false,
"Code": "ApprovedAndClosed"
},
{
"Id": "Cancel",
"Value": "Cancel",
"Text": "Cancel",
"Selected": false,
"Code": "Cancel"
},
{
"Id": "Done",
"Value": "Done",
"Text": "Done",
"Selected": false,
"Code": "Done"
},
{
"Id": "Init",
"Value": "Init",
"Text": "Init",
"Selected": false,
"Code": "Init"
},
{
"Id": "ReadyForProcessing",
"Value": "ReadyForProcessing",
"Text": "ReadyForProcessing",
"Selected": false,
"Code": "ReadyForProcessing"
},
{
"Id": "Rejected",
"Value": "Rejected",
"Text": "Rejected",
"Selected": false,
"Code": "Rejected"
},
{
"Id": "Reminder",
"Value": "Reminder",
"Text": "Reminder",
"Selected": false,
"Code": "Reminder"
}
]
You can try using a filter:
{{(model.Options | filter:{'Selected': true}).length}}
You could use lodash for this:
var countSelected = _.filter(Options, { 'Selected': true});
console.log(countSelected.length);
See: codepen example

Categories

Resources