Multiple select2 angularUI load remote data - angularjs

I have an issue with loading remote data in multiple select2. My code is
var fetchGroups = function (queryParams) {
console.log(JSON.stringify(queryParams));
return $http.get("https://******/****/***/" + queryParams.data.query).then(queryParams.success);
};
$scope.groupSelectOptions= {
minimumInputLength: 3,
ajax: {
data: function (term, page) {
return { query: term };
},
quietMillis: 500,
transport: fetchGroups,
results: function (data, page) {
console.log(data);
// parse the results into the format expected by Select2 return { results: data };
var drastics = data.data.result;
if(drastics){
var data = new Array();
for(var i = 0; i < drastics.length; i++){
data.push(
{
id: drastics[i].id,
text: drastics[i].name
}
);
}
} else {
data = data.data.result;
}
return { results: data };
}
}
};
It returns the values from the get request but when i select it returns undefined at the input box.

Just make sure you've included the 'data' property to the $scope.groupSelectOptions like so :
$scope.groupSelectOptions= {
minimumInputLength: 3,
ajax: {
data: function (term, page) {
return { query: term };
},
.....
data:[]}
You should now see the term selected in the input field.

Related

Angular 5 display result from JSON response

I am trying to access the "list" parameter in the following data set received from [Open weather map][1]. I basically need to access the list layer in the below set where I can get the temp parameter.
{
"cod":"200",
"message":0.0046,
"cnt":37,
"list":[
{
"dt":1518080400,
"main":{
"temp":297.81,
"temp_min":295.457,
"temp_max":297.81,
"pressure":1011.64,
"sea_level":1018.79,
"grnd_level":1011.64,
"humidity":71,
"temp_kf":2.35
},
"weather":[
{
"id":800,
"main":"Clear",
"description":"clear sky",
"icon":"01d"
}
],
"clouds":{
"all":0
},
"wind":{
"speed":3.76,
"deg":322.502
},
"sys":{
"pod":"d"
},
"dt_txt":"2018-02-08 09:00:00"
},
{
"dt":1518091200,
"main":{
"temp":298.03,
"temp_min":296.468,
"temp_max":298.03,
"pressure":1010.47,
"sea_level":1017.64,
"grnd_level":1010.47,
"humidity":65,
"temp_kf":1.57
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03d"
}
],
"clouds":{
"all":48
},
"wind":{
"speed":4.77,
"deg":315
},
"sys":{
"pod":"d"
},
"dt_txt":"2018-02-08 12:00:00"
},
{
"dt":1518102000,
"main":{
"temp":294.89,
"temp_min":294.104,
"temp_max":294.89,
"pressure":1011.17,
"sea_level":1018.11,
"grnd_level":1011.17,
"humidity":77,
"temp_kf":0.78
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03d"
}
],
"clouds":{
"all":44
},
"wind":{
"speed":4.91,
"deg":287.002
},
"sys":{
"pod":"d"
},
"dt_txt":"2018-02-08 15:00:00"
}
]}
I am not sure as to how to go about it. I keep on getting this error "ERROR Error: Cannot find a differ supporting object"
I tried looping through it like below
this.http.get('http://api.openweathermap.org/data/2.5/forecast?id=3362024&APPID=bbcf57969e78d1300a815765b7d587f0').subscribe(data => {
this.items = JSON.stringify(data);
console.log(this.items);
for(var i = 0; i < this.items.length; i++){
this.min = this.items[i].dt;
console.log(this.min);
}
});
Try this. Make sure you import following import on top of the component
import 'rxjs/Rx';
or
import 'rxjs/add/operator/map'
getData(){
this.http.get('https://api.openweathermap.org/data/2.5/forecast?id=3362024&APPID=bbcf57969e78d1300a815765b7d587f0')
.map(res=>res.json()).subscribe(data => {
this.items = data;
console.log(this.items);
for(var i = 0; i < this.items.list.length; i++){
this.min = this.items.list[i].main;
console.log(this.min);
}
});
}
WORKING DEMO
Do console.log(data); and check what kind of data you are getting from API.
If you are getting JSON data from API, then do not do JSON.stringify(data);
If you are getting JSON contained in string then do JSON.parse();
After this you will get JSON in a variable and you can iterate it as follows
Also, do not post your api key in question , others can hit API using your api key
this.http.get('http://api.openweathermap.org/data/2.5/forecast?id=yourId&APPID=yourapikey')
.subscribe(data => {
var res = JSON.parse(data); //if you are getting JSON in a string, else do res = data;
for(var i = 0; i < res.list.length; i++){
console.log(res.list[i].main.temp);
}
});
Considering you are correctly getting json response:=>
One way is :
if you know response in advance and its basic structure is always same then:
you can create a model object similar to the json response and assign the json response to that object and access any values.
e.g.
export class TopLayer{
fieldName1: dataType;
fieldName2: Array<SecondLayer>;
}
export class SecondLayer{
fieldName1: datatype;
fieldName2: ThirdLayer;
}
export class ThirdLayer{
fieldName: datatype
}
another is: assign your json response to a var variable then access what you need:
e.g.
var x = response;
var list = x.list;
We can also do:
this.http.get("some-api-url")
.subscribe((response)=>{
for (let key in response) {
if (response.hasOwnProperty(key)) {
let element = response[key];
let singleData = {id: element.id, value: element.value};
this.dataArray.push(singleData);
}
}
},
(error)=>{
console.log(error)
});
When the response is like [{}, {}, ...]

angular chaining arrays of promises

I am building a website over a database of music tracks. The database is as follows :
music table contains musicid and title
musicrights table contains musicid and memberid
members table contains memberid and memberinfo.
I'm trying to build an array of objects in my database service, which each entry represents a track containing its rightholders (contains information aubout one rightholder but not his name) and their member info (contains name etc). The backend is sailsjs and the code is as follows :
angular.module("myapp").service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberid: rightHolder.memberid
})).then(function (res) {
rightHolder.member = res.data[0];
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/musicrights?where=" + JSON.stringify({
musicid: doc.musicid
})).then(function(res) {
// array of promises :
// each rightholder of a document has to solve member info
var rightHolders = [];
for (var i in res.data) {
var rightHolder = {
member: res.data[i].memberid,
type: res.data[i].membertype,
rights: res.data[i].memberrights
};
rightHolders.push(getHolderMember(rightHolder));
}
return ($q.all(rightHolders));
}).then(function(rightHolders) {
// expected array of one or two rightholders,
// enriched with member information
// actually returns array of one or two arrays of 30 members
// without rightholder info
console.log(rightHolders);
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
// array of 30 promises :
// each one of 30 documents has to resolve its rightholders
var documents = [];
for (var i in res.data) {
documents.push(getRightHolders(res.data[i]));
}
return ($q.all(documents));
}));
}
return (database);
}]);
The first array of promises seems to work as expected, but not the second one in getRightHolders. What is strange is that this function returns an array of one or two promises, which are rightHolders waiting for their memberinfo. But in the callback where I console.log the response, i get an array of one or two (as per the number of pushed promises) but this array's elements are arrays of 30 memberinfo instead of one memberinfo. I don't understand how this $q.all() call gets mixed with the previous-level $q.all.
The data structure is roughly like this
documents [ ] ($http => 30 responses)
music.musicid
music.rightHolders [ ] ($http => 1, 2, 3 responses)
rightholder.rights
rightholder.member ($http => 1 response)
member.memberinfo
Any help appreciated. Thank you !
UPDATE : Thank you for your answer, it worked like a charm. Here's the updated code, with also the migrate service which formats data differently (there is some database migration going on). I kept it out of the first example but your answer gave me this neat syntax.
angular.module("myApp").service("database", ["$q", "$http", "migrate", function($q, $http, migrate) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberID: rightHolder.member
})).then(function(res) {
return (migrate.member(res.data[0]));
}).then(function(member) {
rightHolder.member = member;
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/rightHolders?where=" + JSON.stringify({
musicID: doc.musicID
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.rightHolder)
.map(getHolderMember)
)
);
}).then(function(rightHolders) {
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
},
{
subtitle: {
contains: q
}
}
]
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.music)
.map(getRightHolders)
)
);
}));
}
return (database);
}
I'm not quite sure how you're getting the result you describe, but your logic is more convoluted than it needs to be and I think this might be leading to the issues you're seeing. You're giving the getRightsHolders function the responsibility of returning the document and based on your comment above, it sounds like you previously had the getHolderMember() function doing something similar and then stopped doing that.
We can clean this up by having each function be responsible for the entities it's handling and by using .map() instead of for (please don't use for..in with arrays).
Please give this a try:
angular
.module("myapp")
.service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(memberId) {
var query = JSON.stringify({ memberid: memberid });
return $http.get("/api/members?where=" + query)
.then(function (res) {
return res.data[0];
});
}
function populateRightsHolderWithMember(rightsHolder) {
return getHolderMember(rightsHolder.memberid)
.then(function (member) {
rightsHolder.member = member;
return rightsHolder;
});
}
function getRightHolders(doc) {
var query = JSON.stringify({ musicid: doc.musicid });
return $http.get("/api/musicrights?where=" + query)
.then(function(res) {
return $q.all(res.data.map(populateRightsHolderWithMember));
});
}
function populateDocumentWithRightsHolders(document) {
return getRightsHolders(document)
.then(function(rightsHolders) {
document.rightsHolders = rightsHolders;
return document;
});
}
database.music = function(q) {
return $http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
return $q.all(res.data.map(populateDocumentWithRightsHolders));
});
}
return (database);
}]);

Ag-Grid - Saving columns for future use

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.

Cannot read property 'push' of undefined in AngularJS

I have a factory that calls 4 json files and then I want to do some treatmenet for each data from these files and push them into an array of objects this is the code I wrote :
myapp.factory('wordsCloudFactory', function($http) {
var factory = {
getList: function() {
return $http.get('data/periode_1_file.JSON')
.then(function(response1) {
return $http.get('data/periode_2_file.JSON')
.then(function(response2) {
return $http.get('data/periode_3_file.JSON')
.then(function(response3) {
return $http.get('data/periode_4_file.JSON')
.then(function(response4) {
var words = [{
'period1': [],
'period2': [],
'period3': [],
'period4': []
}];
console.log(words);
for (var i = response1.data['X_id'].length - 1; i >= 0; i--) {
words['period1'].push({
id: response.data['X_id'][i],
count: response.data['count'][i]
});
};
for (var i = response2.data['X_id'].length - 1; i >= 0; i--) {
words['period2'].push({
id: response.data['X_id'][i],
count: response.data['count'][i]
});
};
for (var i = response3.data['X_id'].length - 1; i >= 0; i--) {
words['period3'].push({
id: response.data['X_id'][i],
count: response.data['count'][i]
});
};
for (var i = response4.data['X_id'].length - 1; i >= 0; i--) {
words['period4'].push({
id: response.data['X_id'][i],
count: response.data['count'][i]
});
};
return words;
}, function(error) {
return 'There was an error getting data';
})
}, function(error) {
return 'There was an error getting data';
})
}, function(error) {
return 'There was an error getting data';
})
}, function(error) {
return 'There was an error getting data';
})
}
};
return factory;
})
this code it doesnt work it shows me an error message : 'Cannot read property 'push' of undefined'.
How can I solve this ?
As you can see in my code there are a lot of nested $http.get methodes isn't there another way to write that ?
Your words is an array of object
var words = [{
'period1': [],
'period2': [],
'period3': [],
'period4': []
}];
You have to access it by index.
Try like this
words[0]['period1'].push({
id: response.data['X_id'][i],
count: response.data['count'][i]
});
JSFIDDLE
If it's just an object Like
var words = {
'period1': [],
'period2': [],
'period3': [],
'period4': []
};
Then your push was ok .
words['period1'].push({
id: response.data['X_id'][i],
count: response.data['count'][i]
});
JSFIDDLE

Loading store dynamically based on visible page data for Ext.grid.Panel column

Below is a renderer for an Ext.grid.Panel column. Suppose contactStore has 2,000 values in it and all I care about is the name of the record based on the id (value parameter in this case), and my grid only has 25 rows/records in it for the page I'm on. How can I dynamically get the store so that I grab the relevant associated records (based on the foreign key) of the id of my grid column, rather than loading all 2,000 records? Is there a way to load the store and then in the callback, somehow have this "renderer" function display the values after the callback succeeded?
columns: [{
...
}, {
header: 'Contact Name',
flex: 1,
sortable: true,
dataIndex: 'contact_id',
renderer: function(value) {
var contactStore = Ext.StoreManager.lookup('Contacts');
return contactStore.getById(value).get('full_name');
}
}, {
You can adjust the collectData(records, startIndex) in the viewConfig for that:
Ext.create('Ext.grid.Panel', {
(...)
viewConfig: {
//this method needs to be adjusted
collectData: function(records, startIndex) {
var me = this;
//we can use a custom function for this
if (me.onBeforeCollectData) {
me.onBeforeCollectData(records);
}
var data = me.superclass.collectData.call(me, records, startIndex);
return data;
},
onBeforeCollectData: function(records) {
var newExtraParams = [];
var oldExtraParams;
var needToLoadStore = false;
var contactStore = Ext.StoreManager.lookup('Contacts');
if (contactStore) {
oldExtraParams = contactStore.oldExtraParams;
} else {
//don't use autLoad: true, this will be a local store
contactStore = Ext.create('Ext.data.Store', {
storeId:'Contacts',
(...)
});
needToLoadStore = true;
}
for (var x in records) {
//contact_id is read out here
var param = records[x].get('contact_id');
if (param) {
if (needToLoadStore == false && Ext.Array.contains(oldExtraParams, param) == false) {
needToLoadStore = true;
}
newExtraParams.push(param);
}
}
if (needToLoadStore == true) {
//we use this to load the store data => because of async: false property
Ext.Ajax.request({
scope: this,
//this is for synchronous calls
async: false,
url: (...),
method: (...),
params: newExtraParams,
success: function (res, opt) {
var responseObj = Ext.decode(res.responseText, false);
contactStore.loadData(responseObj); //or deeper in the responseObj if needed
contactStore.oldExtraParams = newExtraParams;
}
});
}
}
}
});

Resources