how make ng-model work separately inside array of objects? - javascript

I'm stuck with some concept while realizing checkbox system.
I've got an array of objects, it looks like this:
this.columnsGroups = [
{
id: 1,
title: 'General requests',
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined
},
{
title: 'ID',
filterType: 'number',
visible: undefined
}
]
},
{
id: 2,
title: 'Technical Requests',
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined
},
{
title: 'ID',
filterType: 'number',
visible: undefined
}
]
},
{
id: 3,
title: 'Popular requests',
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined
},
{
title: 'ID',
filterType: 'number',
visible: undefined
}
]
},
{
id: 4,
title: 'Misc requests',
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined
},
{
title: 'ID',
filterType: 'number',
visible: undefined
}
]
}
]
What I'm trying to do is to parse this array into html template with checkboxes.
The structure of the template consists of: parent checkbox
<div class="ln-select-columns-content" ng-if="currentTab.isAdvancedSearch" ng-repeat="group in ctrl.columnsGroups" ng-style="{'width':'25%'}">
<div class="ln-select-column-row">
<label>
<span class="ln-checkbox">
<input type="checkbox" ng-model="allChecked" ng-checked="allSelected" ng-click="ctrl.toggleSelectAllAttributes()"/>
<span class="ln-bg"></span>
</span>
<div class="ln-select-column-name"><b>{{group.title}}:</b></div>
</label>
<div ng-repeat="column in group.props" class="ln-select-column-row">
<label>
<span class="ln-checkbox">
<input type="checkbox" ng-model="column.visible" />
<span class="ln-bg"></span>
</span>
<span class="ln-select-column-name">{{column.title}}</span>
</label>
</div>
</div>
</div>
Literally, the template view looks like this:
view screenshot
Now, the problem is: when I'm writing a realisation for checkboxing all the child checkboxes with parent checkbox for each column, ng-model=allChecked checks all the child checkboxes from any parent checkbox in the container.
What would be the best way to do parent checkboxing, isolated from the sibling parent checkboxes?
Or maybe the array of objects is not correctly structured?

You have to modify your JSON object a little bit by adding a selected property for tracking ng-model of each checkbox. Then you can write methods in your $scope to trigger on ng-change of each checkbox and toggle checkboxes by modifying JSON object.
For complete solution please see below snippet.
angular.module('app', []).controller('HomeCtrl', function($scope) {
$scope.toggleGroup = function(group) {
if (group.selected) {
group.props.forEach(function (prop) {
prop.selected = true
})
} else {
group.props.forEach(function (prop) {
prop.selected = false
})
}
}
$scope.selectProp = function(group) {
var allSelected = true;
group.props.forEach(function (prop) {
allSelected = allSelected && prop.selected;
})
group.selected = allSelected;
}
$scope.columnsGroups = [
{
id: 1,
title: 'General requests',
selected: false,
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined,
selected: false
},
{
title: 'ID',
filterType: 'number',
visible: undefined,
selected: false
}
]
},
{
id: 2,
title: 'Technical Requests',
selected: false,
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined,
selected: false
},
{
title: 'ID',
filterType: 'number',
visible: undefined,
selected: false
}
]
},
{
id: 3,
title: 'Popular requests',
selected: false,
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined,
selected: false
},
{
title: 'ID',
filterType: 'number',
visible: undefined,
selected: false
}
]
},
{
id: 4,
title: 'Misc requests',
selected: false,
props: [
{
title: 'Search level',
filterType: 'entry',
visible: undefined,
selected: false
},
{
title: 'ID',
filterType: 'number',
visible: undefined,
selected: false
}
]
}
]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="HomeCtrl">
<div ng-repeat="group in columnsGroups">
<input type="checkbox" ng-model="group.selected" ng-change="toggleGroup(group)"/> {{group.title}}
<ul>
<li ng-repeat="prop in group.props">
<input ng-change="selectProp(group)" ng-model="prop.selected" type="checkbox"/> {{prop.title}}
</li>
</ul>
</div>
<pre>
{{columnsGroups | json}}
</pre>
</div>
<script src="script.js"></script>
</body>

Related

Nested component error: {#each} only iterates over array-like on drop

I'm trying to create a component that uses nested drag and drop from sevelte-dnd-action, using this object:
$forms = [
{
id: hexID(),
title: 'Data - test',
defined: true,
components: [
{
id: hexID(),
type: 'text',
size: 'long',
placeholder: 'None'
},
{
id: hexID(),
type: 'text',
size: 'normal',
placeholder: 'Test'
},
{
id: hexID(),
type: 'text',
size: 'normal',
placeholder: 'CCC'
},
{
id: hexID(),
type: 'text',
size: 'normal',
placeholder: 'CDS'
}
]
},
{
id: hexID(),
title: 'Emails',
defined: true,
components: [
{
id: hexID(),
type: 'text',
size: 'normal',
placeholder: 'RGzzzz'
},
{
id: hexID(),
type: 'select',
size: 'normal',
placeholder: 'RGrrr'
}
]
},
{
id: hexID(),
title: 'Tel',
defined: true,
components: [
{
id: hexID(),
type: 'text',
size: 'normal',
placeholder: 'RaaaG'
},
{
id: hexID(),
type: 'select',
size: 'normal',
placeholder: 'Rtrea'
}
]
}
]
I call it first at the app.svelte and pass the array inside the object to the Horizontal.svelte component:
<section class='create_form_body'
use:dndzone={{items:$forms}}
on:consider={handleDndConsider}
on:finalize={handleDndFinalize}>
{#each $forms as form (form.id)}
<HorizontalList {form}/>
{/each}
this is the Horizontal component:
<script>
export let form
function handleDndConsider(cid, e) {
let chosenOne = $forms.findIndex(x => x.id === cid)
$forms[chosenOne].components = e.detail.items;
$forms = [...$forms]
}
function handleDndFinalize(cid, e) {
let idx = $forms.findIndex(x => x.id === cid)
$forms[idx].components = e.detail.items;
$forms = [...$forms]
}
</script>
<div class='form_box'>
<div class='form_header'>
{form.title}
<div class='form_header_combo'>
<span>title</span>
</div>
</div>
<section class='input_list'
use:dndzone={{items: form.components}}
on:consider={(e) => handleDndConsider(form.id, e)}
on:finalize={(e) => handleDndFinalize(form.id, e)}
>
{#each form.components as component (component.id)}
<ComponentGetter type={component}/>
{/each}
</section>
</div>
if i delete all thee DIVs and leave the section it works perfectly, but with the divs it gives error: {#each} only iterates over array-like objects.Could someone give me a choice other than deleting the divs?
this is the REPL
the cause of the problem was the absence of the key 'type' in the use:dndzone={{items: objectArray, type: 'define name'}}. here is the link to the corrected code REPL

Looking for a more concise approach to manipulate an array with nested data

I'm currently working on an Angular application and want to iterate over an array of objects that have nested data. I want to mutate the existing array when a user clicks a checkbox changing the checked property from false to true and vise Versa. For simplicity sake, I'm only posting the array structure.
I tried
const checklistCashe = [
{
categories: [
{
title: "Administrators",
items: [
{subTitle: "Admin", checked: false},
{subTitle: "Associates", checked: false},
{subTitle: "Hr", checked: false},
]
},
{
title: "Associates",
items: [
{subTitle: "Admin", checked: false},
{subTitle: "Associates", checked: false},
{subTitle: "Hr", checked: false},
{subTitle: "Users", checked: false},
]
},
{
title: "Organization",
items: [
{subTitle: "Contract", checked: false},
{subTitle: "External", checked: false},
{subTitle: "Internal", checked: false},
]
},
{
title: "Products",
items: [
{subTitle: "Concept", checked: false},
{subTitle: "Demo", checked: false},
{subTitle: "Production", checked: false},
]
},
{
title: "Reporting",
items: [
{subTitle: "Admin", checked: false},
{subTitle: "Associates", checked: false},
{subTitle: "Hr", checked: false},
]
}
]
}
]
const category = "Reporting";
const subCategory = "Admin";
I want to mutate the current array based on the category and subCategory provided. So I only want the checked property to change if the title is Reporting and the subTitle is Admin.
{
title: "Reporting",
items: [
{subTitle: "Admin", checked: true},
{subTitle: "Associates", checked: false},
{subTitle: "Hr", checked: false},
]
}
The best way with what you have would be something like:
function toggleChecked(title, subtitle) {
checklistCashe[0].categories.forEach((category) => {
if (category.title === title) {
category.items.forEach((item) => {
if (item.subTitle === subtitle) {
item.checked = !item.checked;
}
});
}
});
}
However, I feel like you might be better off formatting your checklistCashe to something more like:
const checklistCashe = {
Administrators: {
Admin: false,
Associates: false,
Hr: false
}
[...]
}
Then you can do something more like:
function toggleChecked(title, subtitle) {
checklistCashe[title][subtitle] = !checklistCashe[title][subtitle]
}
and you wouldn't have to iterate.
If you wanna keep it clean then use lodash as shown below
const checkListCache = [
{
categories: [
{
title: 'Administrators',
items: [
{ subTitle: 'Admin', checked: false },
{ subTitle: 'Associates', checked: false },
{ subTitle: 'Hr', checked: false },
],
},
{
title: 'Associates',
items: [
{ subTitle: 'Admin', checked: false },
{ subTitle: 'Associates', checked: false },
{ subTitle: 'Hr', checked: false },
{ subTitle: 'Users', checked: false },
],
},
{
title: 'Organization',
items: [
{ subTitle: 'Contract', checked: false },
{ subTitle: 'External', checked: false },
{ subTitle: 'Internal', checked: false },
],
},
{
title: 'Products',
items: [
{ subTitle: 'Concept', checked: false },
{ subTitle: 'Demo', checked: false },
{ subTitle: 'Production', checked: false },
],
},
{
title: 'Reporting',
items: [
{ subTitle: 'Admin', checked: false },
{ subTitle: 'Associates', checked: false },
{ subTitle: 'Hr', checked: false },
],
},
],
},
];
const category = 'Reporting';
const subCategory = 'Admin';
const { categories } = checkListCache[0];
const selectedCategory = _.find(categories, ['title', category]);
const selectedSubCategory = _.find(selectedCategory.items, ['subTitle', subCategory]);
selectedSubCategory.checked = !selectedSubCategory.checked;
console.log(checkListCache);
You can add safety checks as well before each loop to ensure we have values before manipulating it.
Use nested map calls:
function mutate (arr)
{
return arr.map(innerArr =>
{
return {
title: innerArr.title,
items: innerArr.items.map(item => {
return {
subTitle: item.subTitle,
checked: (innerArr.title === "Reporting" && item.subTitle === "Admin") ? false : item.checked,
};
}),
};
});
}

Data not Displaying correctly while using JqGrid Grouping

I am trying to show data in group using jqGrid. It creates multiple group for same name.
Below is My Code
jQuery("#jqGridManage").jqGrid({
datatype: "local",
data: Projectdata,
colNames: ['Action', 'Opportunity Id', 'Salesforce Opportunity ID', 'Project Name (Opportunity Name)', 'Project Type', 'Type Of Revenue', 'Milestone Description', 'Amount', 'PO Number', 'PO Amount', 'Close Date', 'Assigned To',
'Business Unit', 'Product', 'Channel Name', 'Sales Person', 'Vertical', 'Customer Name', 'Customer Contact','Region'],
colModel: [
{ name: 'actionBtn', search: false, frozen: true, width: 200, align: 'center'},
{ name: 'OpportunityID', index: 'id', frozen: true },//, cellattr: arrtSetting
{ name: 'SalesforceOpportunityId', index: 'invdate', frozen: true },
{ name: 'OpportunityName', index: 'name', frozen: true },
{ name: 'ProjectTypeLongName', index: 'amount', frozen: true },
{ name: 'ProjectTypeChildName', index: 'tax', frozen: true },
{ name: 'ChannelName', index: 'total', frozen: true },
{ name: 'Amount', index: 'amount' },
{ name: 'PONumber', index: 'closedate' },
{ name: 'POAllocatedAmount', index: 'closedate' },
{ name: 'CloseDate', index: 'closedate' },
{ name: 'AssignedTo', index: 'note' },
{ name: 'BusinessUnit', index: 'note' },
{ name: 'Product', index: 'product' },
{ name: 'Channel Name', index: 'stage' },
{ name: 'SalesPerson', index: 'salesperson' },
{ name: 'Vertical', index: 'vertical' },
{ name: 'CustomerName', index: 'customername' },
{ name: 'CustomerContactNumber', index: 'currency' },
{ name: 'Region', index: 'amountexpected' }
],
shrinkToFit: false,
pager: "#jqGridPagerManage",
viewrecords: true,
autowidth: true,
height: 450,
sortname: "OpportunityID",
grouping: true,
groupingView: {
groupField: ["OpportunityID"],
groupColumnShow: [true, true],
groupCollapse: false,
groupDataSorted: true
},
resizeStop: function () {
resizeColumnHeader.call(this);
fixPositionsOfFrozenDivs.call(this);
fixGboxHeight.call(this);
},
loadComplete: function () {
fixPositionsOfFrozenDivs.call(this);
},
gridComplete: function () {
var ids = $("#jqGridManage").jqGrid('getDataIDs');
for (var i = 0; i < ids.length; i++) {
var rowId = ids[i],
// statusId = $("#list").jqGrid ('getCell', rowId, 'statusId'),
// activeBtn = "";
// if (statusId == 0) { // Inactive
activeBtn = "<button class='ManageEditBtn ManageEdit'><i class='fa fa-edit'></i> Edit</button> <button class='ManageEdit ManageCreate'><i class='fa fa-plus'></i> Create Invoice</button>";
//"onclick='publish(" + rowId + ")' />";
// }
jQuery("#jqGridManage").jqGrid('setRowData', rowId, { actionBtn: activeBtn });
}
},
})
In my code data coming from backend. I am grouping by OpportunityID; there are 4 opprtunity id's but each group is showing multiple times. Below is My screenshow for reference.
I have referred other same questions also but that are not helpful. Can anybody help me in this?
colModel, which you use have many inconsistencies. You should remove of index properties. If you use index in combination with datatype: "local", then the value of index property should corresponds the name property or to reference name of another column of colModel. The best choice is not using any index property at all.
Additionally you have to fix the name of Channel Name column. The value of name property will be used for building ids of some internal elements on the HTML page and HTML5 don't allow the usage of spaces in id.
The problem IMHO is that your data coming from the server should be sorted by OpportunityID. Check if this is true.
Another cause can be in your gridComplete event. Remove this event and see if the grouping is ok.

Show menu items when click on any item

Extjs Menu hide when clicked on any item. I want to show menu even when someone click on menu Item.
Fiddle: https://fiddle.sencha.com/#view/editor&fiddle/1nfo
Ext.create('Ext.button.Button', {
text:'menu open',
id: 'todostatusFilter',
renderTo:Ext.getBody(),
menu: {
xtype: 'menu',
id: 'todostatusFilterMenu',
items: [{
text: 'All',
action: 'All',
checked: true,
group: 'todoSortByStatus'
},{
text: 'incomplete',
action: 'Incomplete',
checked: false,
group: 'todoSortByStatus'
}, {
text: 'Complete',
action: 'Complete',
checked: false,
group: 'todoSortByStatus'
}]
}
});
You can try this - add enableToggle: true to the button, and add a listener on beforehide of the menu like:
button = Ext.create('Ext.button.Button', {
text: 'menu open',
id: 'todostatusFilter',
renderTo: Ext.getBody(),
enableToggle: true,
menu: {
xtype: 'menu',
id: 'todostatusFilterMenu',
listeners: {
beforehide: function () {
return !button.pressed;
}
},
items: [{
text: 'All',
action: 'All',
checked: true,
group: 'todoSortByStatus'
}, {
text: 'incomplete',
action: 'Incomplete',
checked: false,
group: 'todoSortByStatus'
}, {
text: 'Complete',
action: 'Complete',
checked: false,
group: 'todoSortByStatus'
}]
}
});
https://fiddle.sencha.com/#view/editor&fiddle/1nfp

Seaching for node in ExtJs tree

I want to search for specific node in an ExtJs tree. The current code that I have allows node to be searched only at the first level. Please check this fiddle
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [{
text: "Javascript",
leaf: true
}, {
text: "ASP.net",
leaf: true
}, {
text: "Also ASP.net",
leaf: false,
children: [{
text: '1.1 foo',
leaf: false,
children: [{
text: "1.1.1 asp.net mvc",
expanded: true
}, {
text: "1.1.2 java",
expanded: true
}, {
text: "1.1.3 extjs",
expanded: true
}]
}, {
text: '1.2 bar',
leaf: true
}]
}, {
text: "ASP.net future",
leaf: true
}]
}
});
Ext.create('Ext.tree.Panel', {
title: 'Example Tree',
width: 200,
height: 450,
store: store,
rootVisible: false,
multiSelect: true,
renderTo: Ext.getBody(),
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
items: [{
text: 'Search for ASP.net',
handler: function () {
var me = this,
panel = me.up('panel'),
rn = panel.getRootNode(),
regex = new RegExp("ASP.net");
rn.findChildBy(function (child) {
var text = child.data.text;
if (regex.test(text) === true) {
console.warn("selecting child", child);
panel.getSelectionModel().select(child, true);
}
});
}
}]
}]
});
What I want:
Ability to search across all the levels in the tree
once a node is found, I want to expand it.
How can I achieve this?
Thank you
You can use this :
var c = rn.findChild("text","Also ASP.net",true);
c.expand();
true indicates a deep search.Please have a look at findChild.
Please check out the fiddle
This is what I was looking for : http://jsfiddle.net/tdaXs/17/
Thank you Devendra for suggesting Deep Search option.
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [{
text: "Javascript",
leaf: true
}, {
text: "ASP.net",
leaf: true
}, {
text: "Also ASP.net",
leaf: false,
children: [{
text: '1.1 foo',
leaf: false,
children: [{
text: "1.1.1 ASP.net mvc",
leaf: true,
expanded: true
}, {
text: "1.1.2 java",
leaf: true,
expanded: true
}, {
text: "1.1.3 extjs",
leaf: true,
expanded: true
}]
}, {
text: '1.2 bar',
leaf: true
}]
}]
}
});
Ext.create('Ext.tree.Panel', {
title: 'Example Tree',
width: 200,
height: 450,
store: store,
rootVisible: false,
multiSelect: true,
renderTo: Ext.getBody(),
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
items: [{
text: 'Search for ASP.net',
handler: function () {
var me = this,
panel = me.up('panel'),
rn = panel.getRootNode(),
regex = new RegExp("ASP.net");
//var c = rn.findChild("text", " asp.net", true);
rn.findChildBy(function (child) {
var text = child.data.text;
if (regex.test(text) === true) {
console.warn("selecting child", child);
panel.getSelectionModel().select(child, true);
}
});
}
}]
}]
});

Categories

Resources