const displayDataTypes = [];
const TypeMap = {
data: ['type2', 'type3'],
};
const Type = {
title: 'Type',
values: [
{ label: 'Type-1', value: 'type1', disabled: false },
{ label: 'Type-2', value: 'type2', disabled: false },
{ label: 'type-3', value: 'type3', disabled: false },
{ label: 'type-4', value: 'type4', disabled: false },
{ label: 'type-5', value: 'type5', disabled: false }
]
};
const TypesSelection = TypeMap['data'];
Type.values.forEach((item) => {
const tmp = Object.create(item);
TypesSelection.forEach((type) => {
if (tmp.value !== type) {
tmp.disabled = true;
}
});
displayDataTypes.push(tmp);
});
console.log(displayDataTypes);
In the above code, Every object property disabled is getting true. I need the type2 and type3 should be false and rest should be true because of TypeMap - data.
So the output should be
[
{ label: 'Type-1', value: 'type1', disabled: true },
{ label: 'Type-2', value: 'type2', disabled: false },
{ label: 'type-3', value: 'type3', disabled: false },
{ label: 'type-4', value: 'type4', disabled: true },
{ label: 'type-5', value: 'type5', disabled: true }
]
Try it using the Array.map function:
const output = Type.values.map(v => {
v.disabled = !TypesSelection.includes(v.value);
return v;
})
console.log(output)
This is not only smaller but more readable.
The learn more about the Array.map function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
The issue is in the iteration. At some point tmp.value will be 'type2' and type will be 'type3'. This will cause disabled to get set to true for the 'type2' object.
I think this does what you want.
const Type = {
title: 'Type',
values: [
{
label: 'Type-1',
value: 'type1',
disabled: false,
},
{
label: 'Type-2',
value: 'type2',
disabled: false,
},
{
label: 'type-3',
value: 'type3',
disabled: false,
},
{
label: 'type-4',
value: 'type4',
disabled: false,
},
{
label: 'type-5',
value: 'type5',
disabled: false,
},
],
};
const TypeMap = {
data: ['type2', 'type3']
};
const TypesSelection = TypeMap['data'];
const displayDataTypes = Type.values.map(item => {
const shallowCopy = {...item};
if (TypesSelection.every(type => (type !== shallowCopy.value))) {
shallowCopy.disabled = true;
}
return shallowCopy;
});
console.log(displayDataTypes);
I would recommend not using a property named "disable" because it causes confusing double negative situations. Instead use "enabled". This is of course assuming you have control of the property names.
If you don't need to preserve the initial "disabled" states on the copies and if you don't need copies then use the much smaller / simpler implementation in Ilijaz's answer.
Your code is failing because the correct result is being overwritten by other iterations of your inner loop.
Your current structure is 2-step:
Loop over each value in Type.values
Loop over each value in TypeMap.data and check if the two elements don't match
As a result of that second step, even elements that match will get compared to another element that doesn't match, causing the conditional code to get executed anyway.
Eg.:
Outer loop:
item is type2
Inner loop:
type is type2
check the condition: type2 !== type2 is false
Skip conditional code
Inner loop
type is now type3
check the condition: type3 !== type3 is true
run conditional code, set disabled to true
As such, all disableds will always be set to true.
Using a nested forEach isn't very well suited for this use case, since there's no straightforward way to avoid this problem. If you still want to use forEach for the outer loop, you can, or you could simplify further with map(), as #Ilijaz suggested in another answer.
Using forEach and Array.prototype.includes:
const displayDataTypes = [];
const TypeMap = {
data: ['type2', 'type3'],
};
const Type = {
title: 'Type',
values: [{
label: 'Type-1',
value: 'type1',
disabled: false,
},
{
label: 'Type-2',
value: 'type2',
disabled: false,
},
{
label: 'type-3',
value: 'type3',
disabled: false,
},
{
label: 'type-4',
value: 'type4',
disabled: false,
},
{
label: 'type-5',
value: 'type5',
disabled: false,
},
],
};
const TypesSelection = TypeMap['data'];
Type.values.forEach((item) => {
const tmp = Object.create(item);
if (!TypesSelection.includes(tmp.value)) {
tmp.disabled = true;
}
displayDataTypes.push(tmp);
});
console.log(displayDataTypes);
.as-console-wrapper {
max-height: 100% !important;
}
Related
List used for the nf-multiselect-dropdown :
children: any = [{
id: "Son",
label: 'Son',
isDisabled: false
}, {
id: "Daughter",
label: 'Daughter',
isDisabled: false
}, {
id: "None",
label: 'None',
isDisabled: false
}];
Dropdown settings :
this.dropdownSettingsChildren = {
singleSelection: false,
idField: 'id',
textField: 'label',
selectAllText: 'Select All',
unSelectAllText: 'Unselect All',
itemsShowLimit: 1,
allowSearchFilter: true,
enableCheckAll: false,
};
Logic : When selected the 'None' option, it should make the fields 'isDisabled' as true
onChildrenOptionsSelect(event: any) {
if (event.id.includes('None')) {
for (let ele of this.children) {
if (!(ele.id.includes('None'))) {
ele.isDisabled = true;
}
}
}
this.onChildrenOptionsSelectOperation();
}
onChildrenOptionsDeSelect(event: any) {
if (event.id.includes('None')) {
for (let ele of this.children) {
if (!(event.id.includes('None'))) {
ele.isDisabled = false;
}
}
}
this.onChildrenOptionsSelectOperation();
}
HTML code ->
<ng-multiselect-dropdown class="width-120"
[placeholder]="'Select'" ngDefaultControl
[settings]="dropdownSettingsChildren" [data]="children"
[(ngModel)]="psHistory.maritalStatus.children"
name="dummyname"
(onSelectAll)="onChildrenOptionsSelectAll($event)"
(onDeSelectAll)="onChildrenOptionsSelectAll()"
(onSelect)="onChildrenOptionsSelect($event)"
(onDeSelect)="onChildrenOptionsDeSelect($event)">
</ng-multiselect-dropdown>
When checked the array, the values are properly reflecting but the options in ng-multiselect-dropdown are not disabled
I'd like to reflect the disabled fields on UI as well
I used this link as a reference to my code -> Stackblitz reference
I'm using jquery-querybuilder to build out a query. I'm currently having an issue with adding in selectize as a plugin to allow for autocomplete inside the select inputs. I'm logging the data in the for loop and it prints out the correct data so I know its physically getting the data, but when typing in the input box, there is still no autocomplete and I'm not quite sure where I went wrong.
let totalMachines = [];
var rules_basic = {
condition: 'AND',
rules: [{
}, {
condition: 'OR',
rules: [{
}, {
}]
}]
};
let options = {
plugins: [],
allow_empty: true,
filters: [
{
id: 'machineName',
label: 'Machine Name',
type: 'string',
input: 'text',
operators: ['equal'],
plugin: 'selectize',
values: {
},
plugin_config: {
valueField: 'id',
labelField: 'machineName',
searchField: 'machineName',
sortField: 'machineName',
create: false,
maxItems:3,
plugins: ['remove_button'],
onInitialize: function() {
var that = this;
totalMachines.forEach(function(item) {
that.addOption(item);
console.log(item)
});
}
},
valueSetter: function(rule, value) {
rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
}
},
]
}
$.ajax({
url: '/api-endpoint',
type: 'GET',
contentType: 'application/json',
dataType: 'json',
success: function(response){
console.log(response)
response.forEach((res) => {
totalMachines.push(res[0])
})
console.log(totalMachines)
}
})
.then(() => {
// Fix for Selectize
$('#builder').on('afterCreateRuleInput.queryBuilder', function(e, rule) {
if (rule.filter.plugin == 'selectize') {
rule.$el.find('.rule-value-container').css('min-width', '200px')
.find('.selectize-control').removeClass('form-control');
}
});
$('#builder').queryBuilder(options)
})
It would be extremely helpful if someone could help me figure out how to properly configure this plugin, I've looked at every thread and haven't been able to figure it out.
Here is a simple example, using a local datasource, the namesList array
<script>
$(document).ready(function() {
let namesList = [{ id: '1', name: 'andrew' }, { id: '2', name: 'bob' }, { id: '3', name: 'charles' }, { id: '4', name: 'david' }];
let pluginConfig = {
preload: true,
valueField: 'id',
labelField: 'name',
searchField: 'name',
options: namesList,
items: ['2'],
allowEmptyOption: true,
plugins: ['remove_button'],
onInitialize: function () { },
onChange: function (value) {
console.log(value);
},
valueSetter: function (rule, value) {
rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
},
valueGetter: function (rule) {
var val = rule.$el.find('.rule-value-container input')[0].selectize.getValue();
return val.split(',');
}
}
let filterList = [{
id: 'age',
type: 'integer',
input: 'text'
},
{
id: 'id',
label: 'name',
name: 'name',
type: 'string',
input: 'text',
plugin: 'selectize',
plugin_config: pluginConfig
}];
let options = {
allow_empty: true,
operators: ['equal', 'not_equal', 'greater', 'greater_or_equal', 'less', 'less_or_equal'],
filters: filterList
}
$('#builder').queryBuilder(options);
// Fix for Selectize
$('#builder').on('afterCreateRuleInput.queryBuilder', function (e, rule) {
if (rule.filter.plugin == 'selectize') {
rule.$el.find('.rule-value-container').css('min-width', '200px').find('.selectize-control').removeClass('form-control');
}
});
});
I'd like to check at least one checked field is true and not disabled:
const test =
[ { Title:
{ Article: { checked: true, disabled: true }
, Desc: { checked: false, disabled: false }
} }
, { News:
{ Dashboard: { checked: false, disabled: false}
} }
]
I tried like this:
const checkedItems = () => {
let value = false;
test.forEach(el => Object.entries(el).forEach(([title, checkboxProps]) => {
Object.entries(checkboxProps).forEach(([name, config]) => {
if (config["checked"] && !config["disabled"]) {
value = true
}
})
}))
return value;
};
A couple of flatMaps with Object.values can do it pretty cleanly.
const test = [{
Title: {
Article: {
checked: true,
disabled: true
},
Desc: {
checked: false,
disabled: false
}
}
}, {
News: {
Dashboard: {
checked: false,
disabled: false
}
}
}];
const atLeastOneCheckedAndNotDisabled = test
.flatMap(Object.values)
.flatMap(Object.values) // now we have an array of [{checked, disabled}]
.some(innerObj => innerObj.checked && !innerObj.disabled);
console.log(atLeastOneCheckedAndNotDisabled);
You don't care about the keys, only the values, so Object.values will make things easier to work with than Object.entries.
I have a building list. I am able to fetch the building data into component by storing it into building list state.
There are multiple dropdownlist as a different filters(e.g: status, state, country etc). I want to chain up all the filters and getting filtered data.
Here is the faker data regarding filter structure
const buildingFilters = {
fields: [
{
field: 'id',
title: 'Id',
},
{
field: 'name',
title: 'Name',
},
{
field: 'type',
title: 'Type'
},
{
field: 'status',
title: 'Status'
},
{
field: 'city',
title: 'City'
},
{
field: 'state',
title: 'State'
},
{
field: 'country',
title: 'Country'
},
{
field: 'reporting Zone',
type: 'Reporting Zone'
}
],
filtersType: {
country: {
field: 'country',
listofValues: ['USA', 'CANADA']
},
state: {
field: 'state',
listofValues: ['Maryland', 'New Jersey']
},
city: {
field: 'city',
listofValues: ['Bethesda', 'Monmoth Junction']
},
reporting_zone: {
field: 'reporting_zone',
listofValues: ['RZ1', 'RZ2']
},
status: {
field: 'status',
listofValues: ['Draft', 'Inprogress']
},
type: {
field: 'type',
listofValues: ['Type 1', 'Type 2']
}
}
Now, i am calling this by service to load the initial filters into component. Now,i have to configure it into store.
const defaultState = {
bldgList: emptyArray,
bldgFilter: emptyArray,
filteredData: [],
filterTypes: {
filterByStatus: '',
filterByCountry: '',
filterByState: ''
}
};
const getters = {
filteredData: state => {
return state.filteredData = state.bldgList.slice()
if(state.filterTypes.filterByStatus !== '') {
// not understand how will i do that
}
}
};
const mutations = {
FILTER_FIELD_CHANGE(state,payload) {
// here we need to update Filters change
}
},
const actions = {
async filteredData({commit}, filterTypes) {
commit('FILTER_FIELD_CHANGE', filterTypes)
}
}
This store is not correct i know but how to filter building list based on multiple different filters and chaining filters based on condition.
The getter could call Array.prototype.filter() on the input based on the given filters, one by one. The following example assumes filterByStatus, filterByCountry and filterByState each contain the search term.
const getters = {
filteredData: state => {
let bldgs = state.bldgList
if (state.filterTypes.filterByStatus) {
bldgs = bldgs.filter(b => b.status.includes(state.filterTypes.filterByStatus))
}
if (state.filterTypes.filterByCountry) {
bldgs = bldgs.filter(b => b.country === state.filterTypes.filterByCountry)
}
if (state.filterTypes.filterByState) {
bldgs = bldgs.filter(b => b.state === state.filterTypes.filterByState)
}
return bldgs
}
};
I am working the react-data-grid library to create an filterable datatable in react. All of their examples use the depreciated React.createClass method, and I am trying to refactor to the ES6 Class Components.
Specifically, I am trying to refactor the Filterable Grid example:
demo
source
gist of non-refactored adaption that is working
My refactored code looks like this:
import React from 'react'
import ReactDataGrid from 'react-data-grid'
const { Toolbar, Data: { Selectors } } = require('react-data-grid-addons')
class FilterableTable extends React.Component {
constructor(props) {
super(props);
this._columns = [
{
key: 'id',
name: 'ID',
width: 80
},
{
key: 'task',
name: 'Title',
editable: true
},
{
key: 'priority',
name: 'Priority',
editable: true
},
{
key: 'issueType',
name: 'Issue Type',
editable: true
},
{
key: 'complete',
name: '% Complete',
editable: true
},
{
key: 'startDate',
name: 'Start Date',
editable: true
},
{
key: 'completeDate',
name: 'Expected Complete',
editable: true
}
];
this.state = { rows: this.createRows(1001), filters: {} };
console.log(this.state);
}
getRandomDate = (start, end) => {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString();
}
createRows = () => {
let rows = [];
for (let i = 1; i < 1000; i++) {
rows.push({
id: i,
task: 'Task ' + i,
complete: Math.min(100, Math.round(Math.random() * 110)),
priority: ['Critical', 'High', 'Medium', 'Low'][Math.floor((Math.random() * 3) + 1)],
issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.floor((Math.random() * 3) + 1)],
startDate: this.getRandomDate(new Date(2015, 3, 1), new Date()),
completeDate: this.getRandomDate(new Date(), new Date(2016, 0, 1))
});
}
return rows;
}
getRows = () => {
return Selectors.getRows(this.state);
}
getSize = () => {
return this.getRows().length;
}
rowGetter = ( rowIdx ) => {
let rows = this.getRows();
return rows[rowIdx];
}
handleFilterChange = ({ filter }) => {
let newFilters = Object.assign({}, this.state.filters);
if (filter.filterTerm) {
newFilters[filter.column.key] = filter;
} else {
delete newFilters[filter.column.key];
}
this.setState({ filters: newFilters });
}
onClearFilters = () => {
// all filters removed
this.setState({filters: {} });
}
render() {
return (
<ReactDataGrid
columns={this._columns}
rowGetter={this.rowGetter}
enableCellSelect={true}
rowsCount={this.getSize()}
minHeight={800}
toolbar={<Toolbar enableFilter={true}/>}
onAddFilter={this.handleFilterChange}
onClearFilters={this.onClearFilters} />);
}
}
export default FilterableTable
Issue:
An issue arises when I click the filter button - a new header row is rendered (via the Toolbar component), but there is no input field. This screenshot shows the two examples side by side - my ES6 version on top and the createClass version on the bottom:
I am not sure what is causing this, but have a feeling it might be due to the way I am importing Toolbar ? Any help or a point in the right direction would be greatly appreciated ! (As well as any other suggestions re refactoring this component.)
To enable filtering for a given column, you need to set filterable=true for that column. So, add filterable:true to each object in this._columns. For more info, check http://adazzle.github.io/react-data-grid/examples.html#/filterable-grid.
this._columns = [
{
key: 'id',
name: 'ID',
width: 80
},
{
key: 'task',
name: 'Title',
editable: true,
filterable:true
},
{
key: 'priority',
name: 'Priority',
editable: true,
filterable:true
},
{
key: 'issueType',
name: 'Issue Type',
editable: true,
filterable:true
},
{
key: 'complete',
name: '% Complete',
editable: true,
filterable:true
},
{
key: 'startDate',
name: 'Start Date',
editable: true,
filterable:true
},
{
key: 'completeDate',
name: 'Expected Complete',
editable: true,
filterable:true
}
];