React - populate dropdown from array inside object and filter data - arrays

everyone. I have a React App that is supposed to filter planetarium shows by different criteria. One of the criteria is supposed to have multiple values:
var shows = [
{ id: 1, name: 'Black Holes', showType: 'Full Dome', age: 'All Ages', grade: ['Late Elementary', 'High School'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_blackholes.png'},
{ id: 2, name: 'Astronaut', showType: 'Full Dome', age: 'All Ages', grade: ['Early Elementary,',' Late Elementary', 'High School'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_astronaut.png'},
{ id: 3, name: 'Laser Holidays', showType: 'Laser', age: '18+', grade: ['Late Elementary', 'High School', 'College'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_laserholidays.png'},
{ id: 4, name: 'The Gruffalo', showType: 'Flat Screen', age: 'All Ages', grade: ['Pre-K', 'Kinder'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_gruffalo.png'},
{ id: 5, name: 'Laser iPOP', showType: 'Laser', age: 'All Ages', grade: ['Late Elementary', 'High School', 'College'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_ipop.png'}
];
The "grade" property of the "shows" object can have multiple values, and I decided to put them in an array.
I need two things:
1 - I need to populate the "grade" dropdown with all the possible values, without repeated values;
2 - I need to be able filter shows according to what the user select in that dropdown, similar to what the "Show Type" and "Age" dropdowns. Any idea on how to do this? Thanks.
var shows = [
{ id: 1, name: 'Black Holes', showType: 'Full Dome', age: 'All Ages', grade: ['Late Elementary', 'High School'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_blackholes.png'},
{ id: 2, name: 'Astronaut', showType: 'Full Dome', age: 'All Ages', grade: ['Early Elementary,',' Late Elementary', 'High School'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_astronaut.png'},
{ id: 3, name: 'Laser Holidays', showType: 'Laser', age: '18+', grade: ['Late Elementary', 'High School', 'College'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_laserholidays.png'},
{ id: 4, name: 'The Gruffalo', showType: 'Flat Screen', age: 'All Ages', grade: ['Pre-K', 'Kinder'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_gruffalo.png'},
{ id: 5, name: 'Laser iPOP', showType: 'Laser', age: 'All Ages', grade: ['Late Elementary', 'High School', 'College'], cover:'http://www.starsatnight.org/sciencetheater/assets/File/200x300_ipop.png'}
];
// FilterForm React Class
var FilterForm = React.createClass({
getInitialState: function() {
return {
data: this.props.data,
showType: '',
age: '',
grade: '',
}
},
filterItems: function(val, type){
switch (type) {
case 'showType':
this.setState({showType: val});
break;
case 'age':
this.setState({age: val});
break;
case 'grade':
this.setState({grade: val});
break;
default:
break;
}
},
render: function() {
var filteredItems = this.props.data;
var state = this.state;
["showType", "age", "grade"].forEach(function(filterBy) {
var filterValue = state[filterBy];
if (filterValue){
filteredItems = filteredItems.filter(function(item){
return item[filterBy] === filterValue;
});
}
});
var showTypeArray = this.props.data.map(function(item) {return item.showType});
var ageArray = this.props.data.map(function(item) {return item.age});
// This array gets once instance of all grade options since one show can be good for several grades
var gradeArray = this.props.data.map(function(item){
return item.grade;
});
showTypeArray.unshift("");
ageArray.unshift("");
gradeArray.unshift("");
return(
<div className="container">
<FilterOptions
data={this.state.data}
showTypeOptions={showTypeArray}
ageOptions={ageArray}
gradeOptions={gradeArray}
changeOption={this.filterItems} />
<div className="filter-form">
<FilterItems data={filteredItems} />
</div>
</div>
)
}
});
// FilterOptions React Class
var FilterOptions = React.createClass({
changeOption: function(type, e) {
var val = e.target.value;
this.props.changeOption(val, type);
},
render: function(){
return (
<div className="filter-options">
<div className="filter-option">
<label>Show Type</label>
<select id="showType" value={this.props.showType} onChange={this.changeOption.bind(this, 'showType')}>
{this.props.showTypeOptions.map(function(option) {
return ( <option key={option} value={option}>{option}</option>)
})}
</select>
<label>Age</label>
<select id="age" value={this.props.age} onChange={this.changeOption.bind(this, 'age')}>
{this.props.ageOptions.map(function(option) {
return ( <option key={option} value={option}>{option}</option>)
})}
</select>
<label>Grade</label>
<select id="grade" value={this.props.grade} onChange={this.changeOption.bind(this, 'grade')}>
{this.props.gradeOptions.map(function(option) {
return ( <option key={option} value={option}>{option}</option>)
})}
</select>
</div>
</div>
);
}
});
// FilterItems React Class
var FilterItems = React.createClass({
render: function(){
return(
<div className="filter-items">
<br />
{this.props.data.map(function(item){
return(
<div className="filter-item">{item.id} - {item.name} - {item.showType} - {item.age}</div>
);
})}
</div>
)
}
});
ReactDOM.render(
<FilterForm data={shows}/>,
document.getElementById('show-catalog')
);
<script src="https://unpkg.com/react#15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#15/dist/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<div id="show-catalog"></div>

1) You can get a set of unique values from an array using Set. For example,
var gradeArray = this.props.data.map(function(item){
return item.grade;
});
var uniqueGrades = Array.from(new Set(gradeArray));
2) What is not working about your current code?

Related

Angularjs set checked radio not working

I have 3 radio buttons:
<label ng-repeat="mode in opMode.groupMode" class="radio-inline" title="{{mode.title}}">
<input id="rd{{mode.id}}" type="radio" class="panel-load-radio" ng-model="opdtMode.groupMode"
name="inlineRadioOptions" value="{{mode.id}}"
ng-change="changeOpdtMode(mode.id, '{{opdtMode.groupMode}}')">
{{mode.name}}
</label>
Here is Angularjs code:
$scope.opMode = { groupMode: [
{ name: "ModuleType", title: "Load processes by Module type", id: "ModuleType", isDefault: false },
{ name: "OpGroup", title: "Load processes by Operation group", id: "OpGroup", isDefault: true },
{ name: "MachineType", title: "Load processes by Machine type", id: "MachineType", isDefault: false }
]};
If isChange = true, show confirm mbox. If User click cancel, set oldValue and checked previous radio. I wrote this. However it's not working as expected:
$scope.changeOpdtMode = function (newValue, oldValue) {
if(isChange){
const msg = getMsgById(29, msgLostData);
const r = confirm(msg.value);
if (r === true) {
const lang = $scope.layoutLang.selectedLang;
loadLayout(null, lang, newValue);
window.isChange = false;
} else {
$scope.opdtMode.groupMode = oldValue;
}
}else{
const lang = $scope.layoutLang.selectedLang;
loadLayout(null, lang, newValue);
}
}
After 2 hours researched:
I post my answer here for everyone may see as the same issue.
<label ng-repeat="mode in opMode" class="radio-inline" title="{{mode.title}}">
<input type="radio" class="panel-load-radio" ng-value="mode.id"
ng-model="$parent.opdtMode" ng-change="changeOpdtMode(mode.id, '{{opdtMode}}')">
{{mode.name}}
</label>
Need to remove name="inlineRadioOptions" and add $parent into the model.
$scope.opdtMode = "OpGroup";
$scope.opMode = [{ name: "ModuleType", title: "Load processes by Module type", id: "ModuleType" },
{ name: "OpGroup", title: "Load processes by Operation group", id: "OpGroup" },
{ name: "MachineType", title: "Load processes by Machine type", id: "MachineType" }];
$scope.changeOpdtMode = function (newValue, oldValue) {
if(isChange){
const msg = getMsgById(29, msgLostData);
const r = confirm(msg.value);
if (r === true) {
const lang = $scope.layoutLang.selectedLang;
loadLayout(null, lang, newValue);
window.isChange = false;
} else {
$scope.opdtMode = oldValue;
}
}else{
const lang = $scope.layoutLang.selectedLang;
loadLayout(null, lang, newValue);
}
}

How to filter ng-repeat list on empty string values with an inputfield?

How can I filter an ng-repeat to show all items where a certain columnfield is an empty string? When I try this by typing nothing in the field it always seem to give the full list (wich is expected). I only want to see the person with id 1. How can I adjust the filter that a certain character in the inputfield makes the ng repeat filter on empty fields for the name column.
FiddleJs Example
My view:
<div class="panel-heading">
<h3>Filtered by {{filterValue}}</h3>
<input ng-change="filter()" ng-model="filterValue"/>
</div>
<div class="panel-body">
<ul class="list-unstyled">
<li ng-repeat="p in filteredPeople">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
</ul>
</div>
Controller:
var people = [{
name: '',
age: 32,
id: 1
}, {
name: 'Jonny',
age: 34,
id: 2
}, {
name: 'Blake',
age: 28,
id: 3
}, {
name: 'David',
age: 35,
id: 4
}];
$scope.filter = function (value) {
$scope.filteredPeople = $filter('filter')(people, {
name: $scope.filterValue
});
}
$scope.people = people.slice(0);
Delete your $scope.filter() function in the controller and the ng-change="filter()" in your view. You should change var people array to $scope.people. You also need to delete the line $scope.people = people.slice(0);.
Create a filter function in your controller to only return people whose name property is empty if $scope.filterValue is empty:
$scope.emptyFilter = function(person) {
if ($scope.filterValue.length === 0) {
if (person.name.length === 0) {
return person;
}
} else {
return person;
}
};
Next, update your ng-repeat with the following:
<li ng-repeat="p in people | filter:emptyFilter | filter:{name: filterValue}">

ngTable select all filtered data

I'm trying to select only the rows from an ng-table with filtered data. Using the following code filters the table rows but even the rows that aren't shown are being selected:
controller:
let sampleData = [{id: 1, name: 'John Doe', gender: 'Male'},
{id: 2, name: 'Jane Doe', gender: 'Female'},
{id: 3, name: 'Mary Jane', gender: 'Female'},
{id: 4, name: 'Mary Poppins', gender: 'Female'}];
$scope.tableParams = new NgTableParams({
}, {
dataset: sampleData
});
$scope.checkboxes = {
checked: false,
items: {}
};
$scope.$watch(() => {
return $scope.checkboxes.checked;
}, (value) => {
sampleData.map((item) => {
$scope.checkboxes.items.id = value;
});
});
$scope.$watch(() => {
return $scope.checkboxes.items;
}, () => {
let checked = 0;
let unchecked = 0;
let total = sampleData.length;
sampleData.map((item) => {
if ($scope.checkboxes.items.id) {
checked++;
} else {
unchecked++;
}
});
if (unchecked === 0 || checked === 0) {
$scope.checkboxes.checked = checked === total;
}
angular.element($element[0].getElementsByClassName('select-all')).prop('indeterminate', (checked != 0 && unchecked != 0));
});
html:
<script type="text/ng-template" id="checkbox.html">
<input type="checkbox" ng-model="checkboxes.checked" class="select-all" value="">
</script>
<table class="table" ng-table="tableParams" show-filter="true">
<tr ng-repeat="item in $data track by $index">
<td header="'checkbox.html'">
<input type="checkbox" ng-model="checkboxes.items[item.id]">
</td>
<td data-title="'Name'" filter="{'name': 'text'}">
{{item.name}}
</td>
<td data-title="'Gender'" filter="{'gender': 'text'}">
{{item.gender}}
</td>
</tr>
</table>
When the table is filtered via name or gender, the table rerenders with the filtered data. When you click on the select all checkbox while the table is filtered, the filtered rows are selected. Unfortunately, when you clear the filter, the previously filtered out rows are also selected. The same is true when selecting all the filtered rows and then triggering an action that's supposed to get the selected items. (All ids are selected for the action.)
How can I only select the filtered rows? Thank you.
Okay, I got it to work. I just added a tableData object to the $scope so I can store the filtered data there. That's what I used for checking the selected items.
let sampleData = [{id: 1, name: 'John Doe', gender: 'Male'},
{id: 2, name: 'Jane Doe', gender: 'Female'},
{id: 3, name: 'Mary Jane', gender: 'Female'},
{id: 4, name: 'Mary Poppins', gender: 'Female'}];
$scope.tableData = {
filteredData: [],
checkboxes: {
checked: false,
items: {}
}
};
$scope.tableParams = new NgTableParams({
page: 1,
count: 10
}, {
total: data.length;
getData: ($defer, params) => {
let filter = params.filter();
let count = params.count();
let page = params.page();
let filteredData = filter ? $filter('filter')(data, filter) : data;
params.total(filteredData.length);
$scope.tableData.filteredData = filteredData;
$defer.resolve(filteredData.slice((page - 1) * count, page * count));
}
});
$scope.$watch(() => {
return $scope.tableData.checkboxes.checked;
}, (value) => {
$scope.tableData.filteredData.map((item) => {
$scope.tableData.checkboxes.items[item].id = value;
});
});
$scope.$watch(() => {
return $scope.tableData.checkboxes.items;
}, () => {
let checked = 0;
let unchecked = 0;
let data = $scope.tableData.filteredData;
let total = data.length;
let checkboxes = $scope.tableData.checkboxes;
data.map((item) => {
if (checkboxes.items[item].id) {
checked++;
} else {
unchecked++;
}
});
if (unchecked === 0 || checked === 0) {
checkboxes.checked = checked === total;
}
angular.element($element[0].getElementsByClassName('select-all')).prop('indeterminate', (checked != 0 && unchecked != 0));
});
Not really sure if this is the best way to go about it. Also, this doesn't change the select all checkbox's state to indeterminate when you filter > select all > clear filter.
in your second watch, change to return $scope.tableData.filteredData; may solve your problem

How to use the value in ngRepeat as a dynamic way to access a scope?

I have a set of value that I would like to dynamically generate in my view. How can I go about doing it in the following way?
$scope.mainKeyMapping = [
{
name: 'category1',
otherThings: ''
},
{
name: 'category2',
otherThings: ''
},
{
name: 'category3',
otherThings: ''
},
{
name: 'category4',
otherThings: ''
},
{
name: 'category5',
otherThings: ''
}
];
$scope.category1 = {something....}
$scope.category2 = {something....}
$scope.category3 = {something....}
$scope.category4 = {something....}
$scope.category5 = {something....}
HTML
<div ng-repeat="cat in mainKeyMapping">
{{category1}} // outputs obj
{{cat.name}} // outputs string "category1" <----- how do I output the obj?
</div>
First, put your categories into a collection:
$scope.categories = {
category1: {something....},
category2: {something....}
};
Now simply access the right category in your html:
<div ng-repeat="cat in mainKeyMapping">
{{categories.category1}} // outputs obj
{{categories[cat.name]}} // outputs obj
</div>

How to edit a table row using angluarJS?

I'm searching for a solution to edit in-line table rows. Pretty much like this fiddle, but with populated comboboxes too.
function Ctrl($scope) {
$scope.model = {
contacts: [{
id: 1,
name: "Ben",
age: 28
}, {
id: 2,
name: "Sally",
age: 24
}, {
id: 3,
name: "John",
age: 32
}, {
id: 4,
name: "Jane",
age: 40
}],
selected: {}
};
// gets the template to ng-include for a table row / item
$scope.getTemplate = function (contact) {
if (contact.id === $scope.model.selected.id) return 'edit';
else return 'display';
};
$scope.editContact = function (contact) {
$scope.model.selected = angular.copy(contact);
};
$scope.saveContact = function (idx) {
console.log("Saving contact");
$scope.model.contacts[idx] = angular.copy($scope.model.selected);
$scope.reset();
};
$scope.reset = function () {
$scope.model.selected = {};
};
});
How can I make inline editable comboboxes ? Each line should have a name, age and a group of options.
It would be easier, and I would venture to say nicer, if you use ng-grid instead of html tables. The grid has built-in editing, and you can customize the kind of editor, such that your cell could display as plain text, but use a combo box for editing.
Here is a plunker that shows an editable combo box on the Gender column:
http://plnkr.co/edit/zsxqZNQCnpFySjSWcf1D?p=preview
{field:'gender', displayName: 'Gender', enableCellEdit: true,editableCellTemplate: '<span id="gender"><select ng-class="\'colt\' + col.index" + ng-input="COL_FIELD" ng-model="COL_FIELD" ng-options="c.value as c.name for c in genders"></select></span>'}]
And here is the documentation for ng-grid:
http://angular-ui.github.io/ng-grid/

Resources