NgRepeat filtering complex structure - angularjs

I have been given a complex JSON object to display inside Angular and I'd like to filter it into two lists after having drilled down into the object.
The object structure is:
{
foo:
{
bar:
{
showA: { value: true, type: 'A' },
showB: { value: false, type: 'A' },
showC: { value: true, type: 'A' }
}
}
}
And I'm trying to achieve a list of "false" and "true".
In this case:
Disabled:
showB - Type: A
Enabled:
showA - Type: A
showC - Type: A
I can't filter the object and also can't obtain the "key" of the objects, e.g. "showA".
My attempt of using:
item in profile['foo']['bar'] | filter: { value: false }
Accesses the correct objects but I can't filter or get the "key" of it.
Here is a broken plunkr to demonstrate:
http://plnkr.co/edit/9NniQdo213AuEbf0pghA?p=preview
Any advice would be great!

Check out this working punkr: http://plnkr.co/edit/TdM9P592OXd6Bx81Bmbt?p=preview
It uses a custom filter, myFilter, which makes the filtering task pretty simple. myFilter returns a new object with only the objects having value equal to the value given as second argument to the filter.
app.filter('myFilter', function() {
return function(bar, value) {
var r = {};
for (var key in bar) {
if (bar[key].value == value) {
r[key] = bar[key];
}
}
return r;
}
});
To get the key with ng-repeat, use the following syntax:
<li ng-repeat="(key, item) in profile['foo']['bar'] | myFilter:false">
<input type="checkbox" ng-model="item.value" /> {{ key }}
</li>
If you can alter the structure of $scope.profile, the filtering task would be easier with this structure:
bar: [
{name: 'ShowA', value: false, type: 'A'},
...
]

Related

I can't access the props of my objects (Angular)?

I have this variable in my environment.ts:
featureToggle: {"feature1": true, "feature2: false}
In a service of mine, I want to give these values to a component with a getAll-method, just like:
getAll() {
return environment.featureToggle;
}
In a component I'm having an array and call the servicemethod in my ngOnInit, where I assign the values to my array. Through *ngFor im iterating through the array.
Then I get an ERROR NG0901 IterableDiffers.find.
Yes, it might be, because it is an Object Array, so I would have to convert it in my service first to a normal Array, or assign the values to an interface to work with it?
like
interface FeatureInterface {
feature: string,
isActive: boolean;
}
But I can't even .map through my environments variable nor does forEach work. I also tried Object.keys(environment.featureToggle). Is there any way to access and iterate my properties in my environment.ts and work with them in any component?
Component:
features: FeatureInterface[] = [];
ngOnInit(): void {
this.features = this.featureToggleService.getAllFeatures()
Html:
<div *ngFor="let item of features">
{{item.feature}}
...
Check this out!
let featureToggle = { "feature1": true, "feature2": false, "feature3": true};
const result = Object.entries(featureToggle).filter((e) => e[1]).map((i) => i[0]);
console.log(result);
UPDATE 1:
Based on the requirement(as mentioned in the comments), try this:
let featureToggle = { "feature1": true, "feature2": false, "feature3": true };
const result = Object.entries(featureToggle).map((i) => {
return {
feature: i[0],
isAvailable: i[1]
}
});
console.log(result);
[ { feature: 'feature1', isAvailable: true },
{ feature: 'feature2', isAvailable: false },
{ feature: 'feature3', isAvailable: true } ]

update one element of array inside object and return immutable state - redux [duplicate]

In React's this.state I have a property called formErrors containing the following dynamic array of objects.
[
{fieldName: 'title', valid: false},
{fieldName: 'description', valid: true},
{fieldName: 'cityId', valid: false},
{fieldName: 'hostDescription', valid: false},
]
Let's say I would need to update state's object having the fieldName cityId to the valid value of true.
What's the easiest or most common way to solve this?
I'm OK to use any of the libraries immutability-helper, immutable-js etc or ES6. I've tried and googled this for over 4 hours, and still cannot wrap my head around it. Would be extremely grateful for some help.
You can use map to iterate the data and check for the fieldName, if fieldName is cityId then you need to change the value and return a new object otherwise just return the same object.
Write it like this:
var data = [
{fieldName: 'title', valid: false},
{fieldName: 'description', valid: true},
{fieldName: 'cityId', valid: false},
{fieldName: 'hostDescription', valid: false},
]
var newData = data.map(el => {
if(el.fieldName == 'cityId')
return Object.assign({}, el, {valid:true})
return el
});
this.setState({ data: newData });
Here is a sample example - ES6
The left is the code, and the right is the output
Here is the code below
const data = [
{ fieldName: 'title', valid: false },
{ fieldName: 'description', valid: true },
{ fieldName: 'cityId', valid: false }, // old data
{ fieldName: 'hostDescription', valid: false },
]
const newData = data.map(obj => {
if(obj.fieldName === 'cityId') // check if fieldName equals to cityId
return {
...obj,
valid: true,
description: 'You can also add more values here' // Example of data extra fields
}
return obj
});
const result = { data: newData };
console.log(result);
this.setState({ data: newData });
Hope this helps,
Happy Coding!
How about immutability-helper? Works very well. You're looking for the $merge command I think.
#FellowStranger: I have one (and only one) section of my redux state that is an array of objects. I use the index in the reducer to update the correct entry:
case EMIT_DATA_TYPE_SELECT_CHANGE:
return state.map( (sigmap, index) => {
if ( index !== action.payload.index ) {
return sigmap;
} else {
return update(sigmap, {$merge: {
data_type: action.payload.value
}})
}
})
Frankly, this is kind of greasy, and I intend to change that part of my state object, but it does work... It doesn't sound like you're using redux but the tactic should be similar.
Instead of storing your values in an array, I strongly suggest using an object instead so you can easily specify which element you want to update. In the example below the key is the fieldName but it can be any unique identifier:
var fields = {
title: {
valid: false
},
description: {
valid: true
}
}
then you can use immutability-helper's update function:
var newFields = update(fields, {title: {valid: {$set: true}}})

Angular filter by array that contains search criteria

Does the built in Angular "filter" support filtering an array in the sense that "filter where array contains "
Such as follows:
$scope.currentFilter = "Allentown";
$scope.users = [{
name: "user1",
locations: [
{ name: "New York", ... },
{ name: "Allentown", ... },
{ name: "Anderson", ... },
]
}, ... ];
<div ng-repeat="user in users | filter : { locations: { name: currentFilter } }"></div>
In other words I'm looking to filter to only users with a "locations" array that CONTAINS a location that matches the string by name.
If not, how can I accomplish this with a custom filter?
Your code snippet works as is since Angular 1.2.13. In case you're using an older version (tested on 1.0.1) and don't need to reuse your filtering routine across controllers (in which case you should declare a proper filter), you can pass the built-in filter a predicate function :
<div ng-repeat="user in users | filter : hasLocation">{{user.name}}</div>
And write something like this :
$scope.currentFilter = "Allentown";
$scope.hasLocation = function(value, index, array) {
return value.locations.some(function(location) {
return location.name == $scope.currentFilter;
});
}
Fiddle here.

meteor autoform string array shows empty field

I make edit form for some collection, it has Array fields 'phones', each element is String
When I trying to make afArrayField from this field it shows block with one empty string
Schema:
{phones:
{type: Array,
minCount: 1,
label: "Phones numbers"},
{"phones.$":
{type: String}
}
Template:
{{> afQuickField name="phones" value=phones}}
In object array 'phones' is presented
I've the following:
phones: {
type: [String],
minCount: 1,
label: "Phones numbers"
},
'phones.$': {
autoform: {
afFieldInput: {
type: 'text'
}
}
}
Template helper
Template.home.helpers({
doc: {phones: ['09988765', '0998776']} // this should come from db.findOne
})
In template:
{{#autoForm id='test' schema="Schema.Array" type="update" doc=doc}}
{{> afQuickField name="phones" value=doc.phones}}
{{/autoForm}}
I'm having this:
I've the following package dependencies:
meteor-platform
standard-app-packages
iron:router
iron:layout
aldeed:collection2
aldeed:simple-schema
aldeed:autoform
nemo64:bootstrap
less
accounts-base
accounts-password

Rally App SDK 2.0: Cannot modify QueryFilter object after initial creation

I am trying to dynamically create filters for a rallycardboard by using a QueryFilter object. I first create an array of QueryFilter that contains filtering on one property/value pair. I then check some other fields for values in order to decide whether to add those properties to the QueryFilter. However, it seems that after creation, even though I am able to access the object, it refuses to be appended to.
Here is an example of how it's structured:
var filters = [Ext.create('Rally.data.QueryFilter', {
property: 'attr1',
operator: '=',
value: this.attr1
})];
if (this.attr2 !== "") {
filters[0].and(Ext.create('Rally.data.QueryFilter', {
property: 'attr2',
operator: '=',
value: this.attr2
}));
}
if (this.attr3 !== "") {
filters[0].or(Ext.create('Rally.data.QueryFilter', {
property: 'attr3',
operator: '=',
value: this.attr3
}));
}
It looks like the object returned has to be reassigned inside of an array, like such:
var filters = [Ext.create('Rally.data.QueryFilter', {
property: 'attr1',
operator: '=',
value: this.attr1
})];
if (this.attr2 !== "") {
filters = [filters[0].and(Ext.create('Rally.data.QueryFilter', {
property: 'attr2',
operator: '=',
value: this.attr2
}))];
}
if (this.attr3 !== "") {
filters = [filters[0].or(Ext.create('Rally.data.QueryFilter', {
property: 'attr3',
operator: '=',
value: this.attr3
}))];
}

Resources