highcharts - pulling data from HTML but converting the strings to number - highcharts

I have a HTML table whose tbody tds contains strings, specifically dollar amounts like $1,500, can I parseInt() those before they are read into HC?
The API has some methods under the data attribute like beforeParse but the documentation implies that it only works for CSVs. Are there any methods I could use for this?

You are right, beforeParse works only for data from CSV, but you can also modify your data in complete or parsed callback function.
complete: function(options) {
options.series.forEach(s => {
s.data.forEach(point => {
point[1] = Number(point[1].slice(1));
});
});
}
Live demo: https://jsfiddle.net/BlackLabel/98mayuts/
API Reference:
https://api.highcharts.com/highcharts/data.complete
https://api.highcharts.com/highcharts/data.parsed

Related

Can I use IMPORTXML to scrape a Quora query into Sheets?

I am trying to scrape the results from a Quora search query using ImportXML.
The URL is of this form: https://www.quora.com/search?q=scrape%20Quora&time=year
I've tried using ImportXML, and can't get anything to work. As an example, I inspected the questions, and found they were inside a div with a class name of 'q-text puppeteer_test_question_title'. So I tried to import like this, but I just get #N/A:
importxml("https://www.quora.com/search?q=scrape%20Quora&time=year","//div[#class='q-text puppeteer_test_question_title']")
This is clearly not working: is there a fix or just not possible (and why)?
Thank you.
Quora (as of now) runs on JavaScript and google sheets import formulae do not support the scrapping of JS elements:
You can try to fetch the first 3 responses this way (quickly written, could be improved)
function myFunction() {
var options = {
'muteHttpExceptions': true,
'followRedirects': false
};
var url = 'https://www.quora.com/search?q=scrape%20Quora&time=year'
var jsonStrings = UrlFetchApp.fetch(url,options).getContentText().split('window.ansFrontendGlobals.data.inlineQueryResults.results["')
jsonStrings.forEach((jsonString,i) => {
if (i > 0) {
console.log(jsonString.split('"] = ')[1].split('\n')[0])
}
})
}
and then parse the complex json inside. However, other answers are transmitted by quora when scrolling down by ajax asynchronous request.

Joining Firebase tables in React

I am hoping to display a list of user's notes from a Firebase DB inside of a React app.
After reading through the Firebase recommended approach on structuring data, I've created my database in the flattened format they recommend. The data structure looks something like this:
notes
- [noteKey]
- note: [noteData]
- created_at: [date]
- updated_at: [date]
...
users
- [userKey]
- name: [userName]
- notes
- [noteKey]: true
...
...
Each user has an array called notes, which lists the noteKeys of the notes that they own.
So far I've been able to get the full list of notes (from all users, not what I want), and the user's list of noteKeys. The issue that I'm having is combining those two. I have seen the question about joining tables, but I have more of a React focused question:
In which React function does the join happen?
Right now my code looks like this:
getInitialState: function(){
return {
notesList: []
};
},
componentWillMount: function() {
base = Rebase.createClass('https://appName.firebaseio.com');
base.syncState('notes', {
context: this,
state: 'notesList',
asArray: true,
queries: {
limitToLast: 20
}
});
this.state.notesList.map(function(item, i) {
base.child("notes/" + item['.key'] + "/note").on('child_added', function(snapshot) {
console.log(item['.key'])
});
});
},
I see two issues with this.
When the this.state.notesList.map function is called in componentWillMount, the array hasn't been populated with the Firebase data yet, so it looks like an empty array and returns an error.
Once I solve #1, I'm not sure how to get the user specific notes into it's own array that's accessible by the rest of the component.
--
In which React timeline function should the join be happening?
How do the second table items (the user's notes) get added to an array that is accessible by the rest of the component?
You're working with an async library (re-base) here but you've written synchronous code.
What this means is base.syncState is going to fire off a request to your Firebase instance and in the meantime, your JavaScript is going to just keep happily executing down the line with or without results. It follows that this.state.notesList.map is going to map over an empty array since JS is going to execute faster than a round trip to the server.
Looking at the options available for the syncState method, there's one called then that executes a callback.
then: (function - optional) The callback function that will be invoked when the initial listener is established with Firbase. Typically used (with syncState) to change this.state.loading to false.
This makes me think that it fires after you get your data from Firebase.
Try running your .map in there since you'll actually have the data you want.
componentWillMount: function() {
base = Rebase.createClass('https://appName.firebaseio.com');
base.syncState('notes', {
context: this,
state: 'notesList',
asArray: true,
queries: {
limitToLast: 20
},
then: function() {
this.state.notesList.map(function(item, i) {
base.child("notes/" + item['.key'] + "/note").on('child_added', function(snapshot) {
console.log(item['.key'])
});
});
}
});
}

Knockout mapping is not updating my model

I'm having trouble with a knockout model that is not binding on a subscribed update. I have a C# MVC page that delivers a model to the template which is parsed to Json and delivered raw as part of a ViewModel assignment for ko.applyBindings. I have a subscription to an observable that calls a method to perform an update of the viewModel's data. Irrelevant stuff pulled out and renamed for example usage:
var myViewModel = function (data) {
var self = this;
self.CurrentPage = ko.observable();
self.SomeComplexArray= ko.observableArray([]);
self.Pager().CurrentPage.subscribe(function (newPage) {
self.UpdateMyViewModel(newPage);
});
self.UpdateMyViewModel= function (newPage) {
var postData = { PageNumber: newPage };
$.post('/Article/GetMyModelSearchByPage', postData, function (data) {
ko.mapping.fromJS(data, {}, self);;
});
};
When I perform logging, I can see all of the data, and it all looks correct. The same method is used to produce both the initial model and the updated model. I've used this technique on other pages and it worked flawlessly each time. In this case however, I'm looking for it to bind/update SomeComplexArray, and that's just not happening. If I attempt to do it manually, I don't get a proper bind on the array I get blank. I'm wondering if there is something obvious that I'm doing wrong that I'm just flat out missing.
Edit: I don't know that ko.mapping can be pointed to as the culprit. Standard model changes are also not affecting the interface. Here is something that is not working in a bound sense. I have a p element with visible bound to the length of the array and a div element with a click bound to a function that pops items off of SomeComplexArray. I can see in the console log that it is performing its function (and subsequent clicks result in 'undefined' not having that function). However, the p element never displays. The initial array has only 2 items so a single click empties it:
<p data-bind="visible: SomeComplexArray().length === 0">nothing found</p>
<div data-bind="click: function() { UpdateArray(); }">try it manually</div>
-- in js model
self.UpdateArray = function () {
console.log(self.SomeComplexArray());
console.log(self.SomeComplexArray().pop());
console.log(self.SomeComplexArray());
console.log(self.SomeComplexArray().pop());
console.log(self.SomeComplexArray());
});
Edit 2: from the comment #Matt Burland, I've modified how the pop is called and the manual method now works to modify the elements dynamically. However, the ko.mapping is still not functioning as I would expect. In a test, I did a console.log of a specific row before calling ko.mapping and after. No change was made to the observableArray.
I created a test of your knockout situation in JSFiddle.
You have to call your array function without paranthesis. I tested this part:
self.UpdateArray = function () {
self.SomeComplexArray.pop();
};
It seems to be working on JSFiddle side.
I'm not really sure why, but it would seem that ko.mapping is having difficulty remapping the viewmodel at all. Since none of the fields are being mapped into self my assumption is that there is an exception occurring somewhere that ko.mapping is simply swallowing or it is not being reported for some other reason. Given that I could manually manipulate the array with a helpful tip from #MattBurland, I decided to backtrack a bit and update only the elements that needed to change directly on the data load. I ended up creating an Init function for my viewModel and using ko.mapping to populate the items directly there:
self.Init = function (jsonData) {
self.CurrentPage(0);
self.Items(ko.mapping.fromJS(jsonData.Items)());
self.TotalItems(jsonData.TotalItems);
// More stuff below here not relevant to question
}
The primary difference here is that the ko.mapping.fromJS result needed to be called as a function before the observableArray would recognize it as such. Given that this worked and that my controller would be providing an identical object back during the AJAX request, it was almost copy/past:
self.UpdateMyViewModel= function (newPage) {
var postData = { PageNumber: newPage };
$.post('/Article/GetMyModelSearchByPage', postData, function (data) {
self.Items(ko.mapping.fromJS(JSON.parse(data).Items)());
});
};
This is probably not ideal for most situations, but since there is not a large manipulation of the viewModel occurring during the update this provides a working solution. I would still like to know why ko.mapping would not remap the viewModel at the top level, but in retrospect it probably would have been a disaster anyway since there was "modified" data in the viewModel that the server would have had to replace. This solution is quick and simple enough.

Dynamic source for JQuery UI Autocomplete

I am currently working on a interface which requires an autocomplete of locations.
The list of locations is currently obtained via an AJAX call to a JSON object which is generated dymanically from a URL which has a search parameter of at least three characters.
Is there a way (im guessing most likely using an on key up), to populate the autocomplete by making an ajax call using the input current value and then returning these values in the autocomplete selection, rather than relying on jquery to create the autocomplete list from its source.
What I have currently appears to be inefficient and doesn't work as you might expect (for some reason the autocomplete only appears after four characters).
function buildAutoComplete(fieldId) {
var inputValue = $("#" + fieldId).val()
var resultsList = []
if(inputValue.length > 2) {
get("/location?prefix=" + inputValue,inputHit,inputMiss);
}
function inputHit(result) {
for(var i=0; i<result.length; i++) {
resultsList[i] = result[i].display_text
}
$("#" + fieldId).autocomplete({
source: resultsList
});
}
function inputMiss() {
}
}
$("#originField").keyup(function() {
buildAutoComplete("originField");
});
It turns out I was going about this completely the wrong way.
The autocomplete API which I knew allowed a remote source automatically includes a URL parameter of term, of the input value.
So the resulting code looks like
$("#originField").autocomplete({
minLength: 3,
source: "/location"
});
All it needed was the code at the back of the source to look for the parameter 'term' rather than 'prefix'.
Considerably more stable with a less complex and smaller code base.

Append data to iterator in struts2

Hi friends i am trying to create facebook like pagination in struts2
what i am trying is at the end of the webpage i am calling action class using javascript ajax using below code
<script>
$(window).scroll(function() {
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
console.log("Bottom reached");
var ul = $('.ullist');
var start = ul.children().length;
$.post("postImage.action?", { start: start }, function(session2) {
// Here I am getting json data
alert("inside class " + session2);
});
} else {
console.log("Bottom reached not");
}
});
</script>
The problem is that I have already a list using iterator. Please tell me how to append the value to iterator.
<s:iterator value="#session.list">
.......//here i already have data
</s:iterator>
You don't "append data to the iterator", you append DOM elements to the DOM.
You have two main options:
Return rendered HTML and append it at the end of the page (wherever is appropriate in your DOM), or...
Return JSON (or XML or whatever) and build the DOM dynamically on the client side.
You already have a JSP that renders the same type of information, I'd re-use that chunk of JSP, return rendered HTML, and append it. That said, there are countless jQuery bottomless pagination examples and many plugins–I'd probably just pick one that gets you started and take it from there, and use whatever mechanism your choice uses.

Resources