i am trying to create a new multidimensional array from the data i am getting from 3rd part API.
"output":[
{
"is_indb":false,
"name":"adam",
"tokens":29
},
{
"is_indb":true,
"name":"aaron",
"tokens":2,
},
{
"is_indb":false,
"name":"adam",
"tokens":3,
},
{
"is_indb":false,
"name":"axel",
"tokens":5,
},
{
"is_indb":false,
"name":"andy",
"tokens":5,
},
{
"is_indb":false,
"name":"bob",
"tokens":5,
},
{
"is_indb":false,
"name":"aldo",
"tokens":5,
},
{
"is_indb":false,
"name":"julia",
"tokens":5,
}
]
i would like to create a new array and fill it with data from response.
but i would like to do some pre checks like
take only those whose, is_indb = false
take only those whose, name starts with a
so the final array will be, all those whosse is_indb = true and name starts with a
var newaray = [[adam,29],[adam,3],[axel,5],[andy,5],[aldo,5]];
so far i have tried using _pluck and getting some weird outputs. i am able to get sible elements using _pluck but cant get multiple items.
i can think of logic like this
var newaray = [];
if( (_pluck(msg.output,'is_indb') == false && ((_pluck(msg.output,'name').substring(0, 1) == "a")){
newaray.push( [ _.pluck(msg.output, 'name') , _.pluck(msg.output, 'token')] );
}
Use filter and map:
var filteredOutput = output
.filter(function(elem) {
// The return statement should return true,
// if you want the element to pass into the new array.
return elem.is_indb === false && typeof elem.name === "string" && elem.name.indexOf('a') === 0;
})
.map(function(elem) {
return [elem.name, elem.tokens];
});
or with ES6:
let filteredOutput = output
.filter(elem => elem.is_indb === false && typeof elem.name === "string" && elem.name.indexOf('a') === 0)
.map(elem => [elem.name, elem.tokens])
with ES6 and using regex (inspired by Peter Grainger's answer, but also case insensitive):
let filteredOutput = output
.filter(elem => elem.is_indb === false && /^a/i.test(elem.name))
.map(elem => [elem.name, elem.tokens])
and by the way, what you posted is an array of objects, not a multidimensional array, which is an array of arrays.
You could use a filter then a map?
const output = [
{
"is_indb":false,
"name":"adam",
"tokens":29
},
{
"is_indb":true,
"name":"aaron",
"tokens":2,
},
{
"is_indb":false,
"name":"adam",
"tokens":3,
},
{
"is_indb":false,
"name":"axel",
"tokens":5,
},
{
"is_indb":false,
"name":"andy",
"tokens":5,
},
{
"is_indb":false,
"name":"bob",
"tokens":5,
},
{
"is_indb":false,
"name":"aldo",
"tokens":5,
},
{
"is_indb":false,
"name":"julia",
"tokens":5,
}
]
const transform = output.filter(value => /^a/.test(value.name) && !value.is_indb)
.map(value => [value.name, value.tokens])
console.log(transform)
You can use _.filter and get the output in this form
op = [{ obj1 } ,{obj2}];
but as you want to remove some keys also then you can use _.pick
var op = _.filter(ip , function(obj){
if(obj.is_indb == false && obj.name[0] == 'a'){
return true;
}
else{
return false;
}
})
//so now you have all the entries filtered out
var opAltered = _.pick(op,['name','tokens']);
//you will get this result
/*
opAltered = [
{
name : <something>,
tokens : <something>
},{
...
}
]
*/
or If you want array you can use this
opAltered = _.map(op,['name','tokens'];
I have used more code to make you understand properly you can reduce it once you understand Thanks.
Related
So, I have a function which should be executed in case that a if condition is true. I simply do not know how to implement it in a method. I have the following code:
Meteor.methods({
'popItems': function () {
var date = new Date().getTime();
if ( "check if this.userId && any item in the array 'itemIds' is $gt date" ) {
userManagement.update({
'_id': this.userId
}, {
$pop: {'itemIds': -1}
}
}
);
};
}
});
So, in case the if condition is true, the $pop function should be executed. In case false, it should not. I wrote this for the if clause, but it doesn't work:
if (this.userId && userManagement.find({
'itemIds': {$gt: date}})) {...$pop function...}
Meteor.methods({
'popItems': function () {
var date = new Date().getTime();
if (this.userId && userManagement.find({'itemIds':{ $gt: date}}).count() > 0 ) {
userManagement.update({
'_id': this.userId
}, {
$pop: {'itemIds': -1}
});
}
};
});
Include the query in the update operation as
Meteor.methods({
'popItems': function () {
var date = new Date();
userManagement.update(
{
'_id': this.userId,
'itemIds': { '$gt': date }
},
{ '$pop': { 'itemIds': -1 } }
);
}
});
I've made some assumptions in coming up with the above solution. The first one being itemIds is an array composed of just Date objects e.g.
itemIds: [
ISODate("2017-01-25T06:20:00.000Z"),
ISODate("2017-01-26T06:20:00.000Z"),
ISODate("2017-01-27T06:20:00.000Z"),
...
ISODate("2017-02-25T06:20:00.000Z")
]
The above query in the update operation can also be specified with an $and operator as:
Meteor.methods({
'popItems': function () {
var date = new Date();
userManagement.update(
{
'$and': [
{ '_id': this.userId },
{ 'itemIds': { '$gt': date } },
]
},
{ '$pop': { 'itemIds': -1 } }
);
}
});
I have Angular 2 Search Pipe that filters against an array of Project[]. It works for every property except for one containing an array of strings.
Here is a sample of data model
[{
'Id': 2,
'Title': 'Abc',
'Amount': '200',
'Outcome': ['Outcome 2', 'Outcome 22', 'Outcome 222', 'Outcome 2222']
},
{
'Id': 3,
'Title': 'Abc',
'Amount': '300',
'Outcome': ['Outcome 3', 'Outcome 333', 'Outcome 3333', 'Outcome 33333']
}]
Here is the SearchPipe -
not searching against Outcome array
export class SearchPipe implements PipeTransform {
transform(value, args?): Project[] {
let searchText = new RegExp(args, 'ig');
if (value) {
return value.filter(project => {
if (project) {
return project.Title.search(searchText) !== -1
|| project.Focus.search(searchText) !== -1
|| project.Outcome.forEach(outcome => {
if (outcome.search(searchText) !== -1) {
return true;
}
else {
return false;
}
});
}
});
}
}
}
Any Help would be much appreciated - Thank you!
Your foreach is incorrect. It doesnt return true or false. You can change your pipe to something like this and search if it contains something in the string and then return a boolean accordingly.
Like so:
#Pipe({name: 'Search'})
export class Search implements PipeTransform {
transform(value, args?) {
let searchText = 'test';
if (value) {
return value.filter(project => {
if (project) {
return !project.Outcome.every(outcome => {
return (!outcome.includes(searchText))
});
}
});
}
}
}
Also check the plunker I used to see it working ( https://plnkr.co/edit/ntyDUEwe0HXwjeupqDUr?p=preview )
The problem lies within the forEach loop you do. Returning true or false doesn't do what you expect.
A solution would be to move this logic to a separate function:
export class SearchPipe implements PipeTransform {
transform(value, args?): Project[] {
let searchText = new RegExp(args, 'ig');
if (value) {
return value.filter(project => {
if (project) {
return project.Title.search(searchText) !== -1
|| project.Focus.search(searchText) !== -1
|| this._checkArray(project.Outcome, searchText);
}
});
}
}
_checkArray(arr, search) : boolean {
let found: boolean = false;
arr.forEach(outcome => {
if (outcome.search(search) !== -1) {
return true;
}
})
return found;
}
}
It's untested, and not pretty yet. But you get the general idea
I want to filter filtered results.
I have the following JSON
$scope.JSON = [
{
"Animal": "Horse",
"Status": "awake",
"LastUpdate": {
"$date": 1473248184519
}
},
{
"Animal": "Rabbit",
"Status": "awake",
"LastUpdate": {
"$date": 1473248194240
}
},
{
"Animal": "Rabbit",
"Status": "eating",
"LastUpdate": {
"$date": 1473249639255
}
},
{
"Animal": "Horse",
"Status": "eating",
"LastUpdate": {
"$date": 1473249652549
}
},
{
"Animal": "Horse",
"Status": "sleeping",
"LastUpdate": {
"$date": 1473249656338
}
}
]
and the following filter function
$scope.filtering = filtering;
function filtering(animals){
var temp = [].concat(animals)
var animalsExisting = []; // To keep track of animals already added
return temp.reverse().filter(function(animal){
var notAdded = animalsExisting.indexOf(animal.Animal) === -1;
if(notAdded) {
animalsExisting.push(animal.Animal);
}
return notAdded;
})
}
See also this plunkr:
https://plnkr.co/edit/OQVjB47bpS9fKubO2lum?p=preview
How do I filter the returned Array notAdded with the Status, e.g. I want to show only the last & "eating" animals => result: Rabbit?
First option - Slow, but easy
Easiest way - using native Angular filter
<tr ng-repeat="roll in filtering(JSON) | filter : { Status: 'eating' }">
Second option - quick
Because either Angular will invoke filtering(JSON) on each $digest (which occures pretty often) it would be much better if you render a static list, not the return result of the function.
What I suggest is you rewrite your code to something along the lines
$scope.filters = {
status: null
};
$scope.filteredAnimals = [];
$scope.getLastStatusesForEachAnimal = function() {
var map = {};
return [].concat($scope.JSON)
.reverse()
.filter(function(animal) {
return !map[animal.Animal] ? (map[animal.Animal] = true) : false;
});
};
$scope.filterAnimals = function() {
$scope.filteredAnimals = $scope.getLastStatusesForEachAnimal()
.filter(function(animal) {
return $scope.filters.status ? animal.Status === $scope.filters.status : true;
});
};
$scope.filterAnimals();
Third option - a tad slower, but more elegant
Write your own filter with caching, example
.filter('animalStatusFilter', function() {
var cache = {
params: {},
result: null
};
return function(animals, status, onlyLast) {
var params = {
animals: animals,
status: status,
onlyLast: onlyLast
};
if (validateCache(params)) {
return cache.result;
}
animals = onlyLast ? getLastStatusesForEachAnimal(animals) : animals;
if (status) {
animals = animals.filter(function(animal) {
return status ? animal.Status === status : true;
});
}
cache.params = params;
cache.result = animals;
return animals;
};
function validateCache(params) {
return params.animals === cache.params.animals &&
params.status === cache.params.status &&
params.onlyLast === cache.params.onlyLast
}
function getLastStatusesForEachAnimal(animals) {
var map = {};
return [].concat(animals)
.reverse()
.filter(function(animal) {
return !map[animal.Animal] ? (map[animal.Animal] = true) : false;
});
}
})
I am using the ag-grid for angular1, (and loving it), and I want my users to be able to reorgenize columns, change sortings, and everything, and that it will stay after a refresh.
It should not be very hard, except that the columns are circular (contains pointers to themselves), and thus I cannot parse them.
Code:
var columnDefsKey = "columnDefs["+$rootScope.page+"]";
var savedColumns = localStorage.getItem(columnDefsKey);
function saveColumnsState() {
var currentCol = vm.gridOptions.columnApi.getAllColumns();
if (!angular.equals(currentCol, savedColumns))
try {
localStorage.setItem(columnDefsKey, JSON.stringify(currentCol));
} catch (ex) {
log(ex);
log(currentCol);
}
}
And:
onColumnEverythingChanged: saveColumnsState,
onColumnVisible: saveColumnsState,
onColumnPinned: saveColumnsState,
onColumnResized: saveColumnsState,
onColumnRowGroupChanged: saveColumnsState,
onColumnValueChanged: saveColumnsState,
onColumnMoved: saveColumnsState,
onColumnGroupOpened: saveColumnsState,
It fails on the "try" every time:
TypeError: Converting circular structure to JSON(…) [Column, Column, Column, Column, Column, Column, Column, Column, Column, Column]
How can I do that? (save columns for later use)
If I manage to do that, I will be able to create several views without coding.
you can get the better understanding of the issue from below link
Chrome sendrequest error: TypeError: Converting circular structure to JSON
Also check below reference
https://github.com/isaacs/json-stringify-safe
The way to achieve this was to build my own column model, that I can save and parse again, and in which to save only necessary properties.
This method is XSS vulnerable, as I am evaluating functions, but it is a working solution.
columnsApi: {
key: null,
grid: null,
newColumnModel: {
headerName: "",
width: 200,
valueGetter: "",
filter: 'text',
aggFunc: 'none',
filterParams: {apply: true}
},
setKey: function (key) {
this.key = key;
},
setGrid: function (grid) {
this.grid = grid;
},
format: function (columns) {
var format = [];
angular.forEach(columns, function (col) {
var colDef = {
width: col.actualWidth,
pinned: col.pinned,
hide: !col.visible
};
format.push(angular.extend(col.colDef, colDef));
});
return format;
},
getIDs: function (columns) {
var ids = [];
angular.forEach(columns, function (col) {
ids.push(col.colId);
});
return ids;
},
stringify: function (columns) {
return JSON.stringify(columns, function (key, value) {
if (typeof value === "function")
return "/Function(" + value.toString() + ")/";
return value;
});
},
parse: function (string) {
return JSON.parse(string, function (key, value) {
if (typeof value === "string" &&
value.startsWith("/Function(") &&
value.endsWith(")/")) {
value = value.substring(10, value.length - 2);
return eval("(" + value + ")");
}
return value;
});
},
add: function (column) {
if (this.grid === null) {
console.error("Assertion error: grid must not be null");
return;
}
if(column.aggFunc == 'none')
column.aggFunc = undefined;
var groups = this.get().groups;
var newColumns = this.format(getGridColumns(this.grid));
newColumns.push(column);
this.grid.api.setColumnDefs(newColumns);
this.setGroups(groups);
},
save: function () {
var self = this;
if (this.key === null) {
console.error("Assertion error: key must not be null");
return;
}
if (this.grid === null) {
console.error("Assertion error: grid must not be null");
return;
}
var savedOptions = {
columns: self.format(getGridColumns(self.grid)),
groups: self.getIDs(self.grid.columnApi.getRowGroupColumns()),
sorting: self.grid.api.getSortModel(),
filter: self.grid.api.getFilterModel()
};
localStorage.setItem(this.key, this.stringify(savedOptions));
},
// Get function uses "eval" - XSS vulnerable.
get: function () {
if (this.key === null) {
console.error("Assertion error: key must not be null");
return;
}
var options = localStorage.getItem(this.key);
if (options)
options = this.parse(options);
return options;
},
remove: function (field) {
if (this.grid === null) {
console.error("Assertion error: grid must not be null");
return;
}
var newColumns = this.format(getGridColumns(this.grid));
angular.forEach(newColumns, function (col, key) {
if (col.field == field)
newColumns.splice(key, 1);
});
this.grid.api.setColumnDefs(newColumns);
},
setGroups: function (groups) {
var self = this;
angular.forEach(groups, function (id) {
angular.forEach(getGridColumns(self.grid), function (col) {
if (col.colId == id)
self.grid.columnApi.addRowGroupColumn(col);
});
});
}
}
This solution was written for Ag-Grid 5 I believe, and thus I am not sure if it still holds.
I currently have the code below that overrides the sort for all stores. What I need to do is create a sort for an individual store. How do I do that?
Ext.override(Ext.data.Store, {
// override
createSortFunction: function (field, direction) {
direction = direction || "ASC";
var directionModifier = direction.toUpperCase() == "DESC" ? -1 : 1;
var sortType = this.fields.get(field).sortType;
//create a comparison function. Takes 2 records, returns 1 if record 1 is greater,
//-1 if record 2 is greater or 0 if they are equal
return function (r1, r2) {
var v1;
var v2;
if (field == 'Registered') {
v1 = sortType(r1.data['AircraftNeedsRegistered']);
v2 = sortType(r2.data['AircraftNeedsRegistered']);
if (r1.data['AircraftNeedsRegistered'])
r1.data['Register'] = !r1.data['Register'];
if (r2.data['AircraftNeedsRegistered'])
r2.data['Register'] = !r2.data['Register'];
//store.getAt(rowIndex).data['Registered'] = true;
}
else {
v1 = sortType(r1.data[field]);
v2 = sortType(r2.data[field]);
}
// To perform case insensitive sort
if (v1.toLowerCase) {
v1 = v1.toLowerCase();
v2 = v2.toLowerCase();
}
return directionModifier * (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
};
}
What I want to implement is something like this:
function AircraftStore() {
return new Ext.data.JsonStore(Ext.apply({
url: AVRMS.ROOT_CONTEXT + "/ssl/json/general/GetAircraftByOwnerId.aspx",
idProperty: 'OwnerOid',
baseParams: { OwnerOid: 0 },
fields: ['AircraftOid', 'NNumber', 'Make', 'Model', 'Seats', 'RegistrationType', 'Airworthy', 'IsFaaAirport', 'AirworthyString', 'IsFaaAirportString', 'Airport', 'AircraftNeedsRegistered', 'Register'],
sort: function (field, direction) {
return customSort(field, direction);
}
}));
};
function customSort(field,direction) {
//What do I put here?
}
I am not sure if I understood the purpose of your code correctly but I believe the same effect can be achieved by using the following code (sorry, I haven't tested it but it should work).
AircraftStore = Ext.extend(Ext.data.JsonStore, {
url: AVRMS.ROOT_CONTEXT + "/ssl/json/general/GetAircraftByOwnerId.aspx",
idProperty: 'OwnerOid',
baseParams: {
OwnerOid: 0
},
fields: ['AircraftOid', 'NNumber', 'Make', 'Model', 'Seats', 'RegistrationType', 'Airworthy', 'IsFaaAirport', 'AirworthyString', 'IsFaaAirportString', 'Airport', 'AircraftNeedsRegistered', 'Register'],
sort: function (field, direction) {
if (field == 'Registered') {
field = 'AircraftNeedsRegistered';
this.query('AircraftNeedsRegistered', true).each(function(record) {
record.data['Register'] = !record.data['Register'];
});
}
return AircraftStore.superclass.sort.call(this, field, direction);
}
});
If this does not achieve your desired behaviour because I missed something, you can just override the createSortFunction instead of sort. However, since createSortFunction is supposed to be private, it is better to handle custom logic by overriding sort. Anyway, if you prefer to stay with your first approach, your AircraftStore should look like this:
AircraftStore = Ext.extend(Ext.data.JsonStore, {
url: AVRMS.ROOT_CONTEXT + "/ssl/json/general/GetAircraftByOwnerId.aspx",
idProperty: 'OwnerOid',
baseParams: {
OwnerOid: 0
},
fields: ['AircraftOid', 'NNumber', 'Make', 'Model', 'Seats', 'RegistrationType', 'Airworthy', 'IsFaaAirport', 'AirworthyString', 'IsFaaAirportString', 'Airport', 'AircraftNeedsRegistered', 'Register'],
createSortFunction: function (field, direction) {
// copy your createSortFunction here
};
});