Add Categories to Highcharts via Loop - javascript

I'm trying to add a list of categories as the xAxis for my bar chart using JavaScript and a JSON object. I've thus far had no success as the following code produces the following along the xAxis:
[object Object]
1
2
The JSON object I'm receiving is like this:
0: {Item: "textforyou", Num: 88}
1: {Item: "MoreText", Num: 22}
2: {Item: "SimpleStuff", Num: 85}
I'd like the have the categories on the xAxis look more like this:
textforyou
MoreText
SimpleStuff
This bit of code is where I'm taking my JSON object and trying to get the categories and series data for it.
$.ajax({
xhrFields: { withCredentials: true },
url: areaUrl + "api/Problem/ProblemsYTD",
success: data => {
self.isLoading(false);
self.data(data);
self.setPlotData(data);
self.isLoaded(true);
},
error: data => {
self.loadingError(true);
}
});
}
self.setPlotData = (data: any) => {
var len = data.List.length,
i;
var dataCats = new Array();
for (i = 0; i < len; i++) {
dataCats.push(
{ name: data.List[i].Service }
)
}
self.plotDataLabels.push({ data: dataCats });
var dataItems = [];
for (i = 0; i < len; i++) {
dataItems.push(
{ y: data.List[i].DaysOpen }
)
}
self.plotData.push({ data: dataItems });
}
Lastly, on the page where the bar chart is being created, this is the command I have for the xAxis category section of the page.
xAxis: {
categories: viewModel.plotDataLabels(),
crosshair: false
},
I'm able to do this fine for the series data, but I can't seem to get it right for the categories/text. Any help would be appreciated.
EDIT: Per Request, when I console.log ViewModel.plotDataLabels(), I get a single object back with "data: Array[3]". Once I access that array, everything appears as the following
Dropdown 0: Object
Dropdown 1: Object
Dropdown 2: Object
name: "SimpleStuff"
__proto__: Object

You need to manipulate your ViewModel.plotDatalabels() to ensure you get just the name and not the whole object. This should work, replace your categories value with the following
categories: viewModel.plotDataLabels().map(function(obj){ return obj.name; })

Related

Pushing an object to array using foreach

let inputValues = [];
for (let i = 0; i < inputs.length; i++) {
let inputValue = inputs[i].value;
inputValues.push(inputValue)
}
let newCar = {
Model: inputValues[0],
Brand: inputValues[1],
Date: inputValues[2],
Horsepower: inputValues[3],
Transmission: inputValues[4],
Class: inputValues[5]
}
newData.push(newCar)
Can someone help me push newCar object to newData array using foreach loop. inputs are my inputs. i need to add the input values to my object keys. and push the object to the array. i need to do this in a way where i dont have newCar object declared like this.
There's no need for the loop or the newCar variable, you can put the object directly in the call to push()
newData.push({
Model: inputs[0].value,
Brand: inputs[1].value,
Date: inputs[2].value,
Horsepower: inputs[3].value,
Transmission: inputs[4].value,
Class: inputs[5].value
});
But it should work the same either way.
If we assume that your number of labels is the same as your number of inputs. Then we can do all this work in one loop as seen in the example code snippet example. Feel free to run it and see how it all works.
That being said, it is best to add your divs with the labels themselves so then you can gather the data from the divs rather than having to deal with fixed indexes which could become a problem as you add more labels.
<div data-label="Model">Toyota</div>
Then you will be able to do the below by doing this assuming inputs is an array of divs defined as above
let newData = [];
inputs.forEach((input) => newData.push({
[input.attr('data-label')]: input.text()
}))
But you could shorting this even more by just using a map
let newDate = inputs.map((input) => ({
[input.attr('data-label')]: input.text()
}))
// This method assumes that your divs will have the same number of labels
// We will assume input values are as such. But you can change it to be array of divs
let inputs = [{ value: 'Corolla' }, { value: 'Toyota' }, { value: '2014' }, { value: 'coolHorsies' }, { value: 'coolTransmission' }, { value: 'coolClass' }]
let labels = ['Model', 'Brand', 'Date', 'Horsepower', 'Transmission', 'Class'];
let newData = [];
inputs.forEach((input, idx) => newData.push({
[labels[idx]]: input.value,
}))
console.log(newData)

Objects with and without quotation marks

Edit: using google apps script, these are objects that are passed back from their functions. When I say logged I mean the result of the return function is logged in GAS.
I have objects that serve as profiles for a larger script, and I was trying to generate a larger profile programmatically.
When called and logged:
[ { name: "a1",
functionName:"functionA",
options:{something:"a1run"}
},
{ name: "a2",
functionName:"functionA",
options:{something:"a2run"}
},
{ name: "a3",
functionName:"functionA",
options:{something:"a3run"}
}
]
Shows up in the log as this:
[{
functionName = functionA,
name = a1,
options = {
something = a1run
}
},
}, {
functionName = functionA,
name = a2,
options = {
something = a2run
}
}, {
functionName = functionA,
name = a3,
options = {
something = a3run
}
}]
you'll note that all of the quotation marks disappeared.
Yet when I call an almost identical function where I generated each part of the object with a for loop (this)
var s1 = "";
for (var i=0; i<5;i++)
{
var newString = '';
newString += '{ name: "a'+i+'",';
newString += 'functionName: "functionA",';
newString += 'options:{something: "a'+i+'run"} },';
s1+= newString;
}//for loop
The logged result of the function is this:
[{
name: "a0",
functionName: "functionA",
options: {
something: "a0run"
}
}, {
name: "a1",
functionName: "functionA",
options: {
something: "a1run"
}
}, {
name: "a2",
functionName: "functionA",
options: {
something: "a2run"
}
}, {
name: "a3",
functionName: "functionA",
options: {
something: "a3run"
}
}, {
name: "a4",
functionName: "functionA",
options: {
something: "a4run"
}
}, ]
This is a problem because the initial formatting does work as a profile, and the second one does not. What aspect of JavaScript objects do I need to understand? I didn't think it would make a difference because this object goes through a JSON.stringify when it is used but I was wrong.
My question isn't just how I change it so that it is processed the same way, but why one is being treated differently from the other.
This is not the correct way of creating a JSON array
you should do something like this and forget about creating a string of JSON array
let output = [];
for (var i = 0; i < 5; i++) {
output.push({
name: "a" + i,
functionName: "functionA",
options: {
something: "a" + i + "run"
}
});
}
console.log(output);
Instead of using Logger or the Google Apps Script built-id debugger to "print" your JSON in order to debug it if you are able to use Stackdriver use it or use the HTML Service to print the JSON object to your web browser console instead.
The above becase the Log view (View > Logs), as you already found, not always print JSON objects correctly.
If you want to use Logger, first you should convert to JSON object to string. In most cases using JSON.stringify(...) will work fine.
References
https://json.org/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON

Find if item in collection with value exists

First of all, here is my very simple component :
var RenewedLoanModal = new Vue ({
el: '#myModal',
data:
{
responses: []
}
});
responses is filled up by an ajax call, it is an array of objects.
Here is the structure :
responses: [
{error: 'foo', message: 'foo', id: 'foo', success: true},
{error: 'bar', message: 'bar', id: 'bar', success: false},
...
]
I am trying to know if one of these object have a success: false but I didn't find anyway to check it.
Is there a way to iterate through the responses collection in a method, not in the view rendering ? Or maybe a v-if test ?
There are many ways to check if an item exists in a collection by its properties.
Plain Javascript
The first thing you could do using only plain javascript is the following:
var success = false
for (var i = 0; i < responses.lenth; i++) {
if (responses[i].success === true) success = true
}
ECMAScript 6
You can do it in ES6 like this:
var success = responses.reduce((prev, cur) => prev || cur.success, false)
Functional programming
Another more declarative way is by using the Ramda.js library:
// if 'any' of the elements satisfy the predicate
var success = R.any(response => response.success === true)(responses)
// or more briefly
var success = R.any(response => response.success)(responses)
Hooking it up in Vue.js
After you create say, a computed property with the above return result, you can hook it up to a v-if or a v-show if you want to conditionally display something.
If possible, I would use:
data: {
hadError: false,
responses: []
}
and let the addResponse(data, resp) do the job:
if(resp.success === false) data.hadError = true;
data.responses.push(resp);
otherwise:
for(i=0; i<responses.length; i++) {
if(response[i].success === false)
.....
}

Unable to hold onto variable after fetching JSON data

I am using the highstocks charting library and JQuery for this question. I am attempting to create one chart that is partitioned into three pieces, each with a different set of data. To read in the data, I am using an example from the highstock site, with the following code:
var seriesOptions = [],
names = ['MSFT', 'AAPL', 'GOOG'];
$.each(names, function(i, name) {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function(data) {
seriesOptions[i] = {
name: name,
data: data
};
});
});
After this code is processed, I use the seriesOptions variable as the series value for each of the three charts as such:
$('#container').highcharts('StockChart', {
// misc options
series: [
seriesOptions[0],
seriesOptions[1],
seriesOptions[2],
]
}
However, it seems that the seriesOptions variable is null after it comes out of the $.getJSON() method call. How can I get around this, and what is happening to the seriesOptions variable after the $.getJSON() call?
Thanks
EDIT: Specific error:
Uncaught TypeError: Cannot read property 'type' of undefined. I am pretty sure that this is referring to the seriesOptions variable, but I'll include it for clarity.
You're probably executing the highCharts call before the AJAX call has completed. You're also doing an AJAX call in a loop (albeit a small loop, it can still have the same general issues) - if you can - try and make this 1 AJAX call with all the params. If that's not an option - you can loop, and verify all the calls are done, then process:
var seriesOptions = [],
names = ['MSFT', 'AAPL', 'GOOG'];
var completedCalls = 0;
for (var i = 0; i < names.length; i++) {
var name = names[i];
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function(data) {
seriesOptions.push({
name: name,
data: data
});
completedCalls++;
if (completedCalls == names.length) {
//All ajax calls done, do highcharts magic!
$('#container').highcharts('StockChart', {
// misc options
series: [
seriesOptions[0],
seriesOptions[1],
seriesOptions[2],
]
})
}
});
}
jQuery provides an interface using $.when for resolving multiple ajax calls using deferred/promise objects. An example using your configuration can be seen below.
var seriesOptions = [];
$.when(
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=msft-c.json&callback=?'),
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-c.json&callback=?'),
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=goog-c.json&callback=?')
).done(function (r1, r2, r3) {
seriesOptions.push({
name: "MSFT",
data: r1
});
seriesOptions.push({
name: "AAPL",
data: r2
});
seriesOptions.push({
name: "GOOG",
data: r3
});
$('#container').highcharts('StockChart', {
// misc options
series: [
seriesOptions[0],
seriesOptions[1],
seriesOptions[2],
]
});
});

select2: "text is undefined" when getting json using ajax

I'm having an issue when getting json results back to select2. My json does not return a result that has a "text" field so need to format the result so that select2 accepts "Name".
This code works if the text field in the json is set to "text" but in this case, I cannot change the formatting of the json result (code outside my control).
$("#e1").select2({
formatNoMatches: function(term) {return term +" does not match any items." },
ajax: { // instead of writing the function to execute the request we use Select2's convenient helper
url: "localhost:1111/Items.json",
dataType: 'jsonp',
cache: true,
quietMillis: 200,
data: function (term, page) {
return {
q: term, // search term
p: page,
s: 15
};
},
results: function (data, page) { // parse the results into the format expected by Select2.
var numPages = Math.ceil(data.total / 15);
return {results: data.Data, numPages: numPages};
}
}
});
I have looked into the documentation and found some statements you can put into the results such as
text: 'Name',
but I am still getting "text is undefined".
Thanks for any help.
note that select2 is always in {id,text} pair so you need to specify both
results: function (data, page) {
var newData = [];
_.each(data, function (item) {
newData.push({
id: item.Id //id part present in data
, text: item.DisplayString //string to be displayed
});
});
return { results: newData };
}
},
Thanks to #neel shah for solving my problem. i had just little problem, i didnt wanted to use extra library so thats why i changed to normal jquery.
so if wanna go for normal jquery or javascript.
results: function (data, page) {
var newData = [];
$.each(data, function (index,value) {
newData.push({
id: value.Id, //id part present in data
text: value.DisplayString //string to be displayed
});
});
}
OR
results: function (data, page) {
var newData = [];
for ( var i = 0; i < data.length; i++ ) {
newData.push({
id: data[i].Id, //id part present in data
text: data[i].DisplayString //string to be displayed
});
}
All credits go to neel shah. Thanks again.

Categories

Resources