reload d3 graph when a 'dropdown menu value changes - javascript

I am trying to get my d3.js line chart reloading when the user chooses an item in a dropdown menu, with the data corresponding to this item.
My menu is a list of stock market values:
YHOO
FB
...
For each of these, I have a JSON file with the data.
The graph in itself is working.
I put the code in a [JSFiddle], which doesn't work because it is supposed to use d3 and knockout.js.
It may be easier to work from this Github Gist.
Anyway, the code past line 83 changes newValue for each choice in the dropdown.
The data is stored in yahoo.json and fb.json.
How can I have the graph reloading each time the user selects a new choice in the dropdown menu with the data associated with this choice?
Thank you SO MUCH.
EDIT: temporary hack
/*User's stock choice*/
var viewModel = {
choice: ["AAPL", "YHOO", "FB", "MSFT"],
selectedChoice: ko.observable("two"), /*Knockout.js is used for having an observable array*/
};
viewModel.selectedChoice.subscribe(function(newValue) {
console.log(newValue);
if (newValue === "YHOO") {
d3.select("svg").remove();
d3.json('yahoo.json', draw);
} else if (newValue === "FB") {
d3.select("svg").remove();
d3.json('fb.json', draw);
}
});
ko.applyBindings(viewModel);

You can actually use d3 to bind events to the dropdown menu and then call a function when an on change event occurs. The function would go off and, in your case, grab the stock values from Yahoo. The only real trick is getting the data out of this. I ended up console logging this and digging through until I found __data__. Using d3 means you don't need knockout for this and can remove that code from your example.
Anyway, to set this up you'll need a div to append the dropdown menu and a set of stock names. You can use this list of stock names to create the dropdown menu as shown below.
var names = ["AAPL", "YHOO", "FB", "MSFT"];
d3.select("#dropDown")
.append("select")
.on("change", function() {
change(this.options[this.selectedIndex].__data__);
})
.selectAll("option")
.data(names).enter()
.append("option")
.text(function(d) {
return d;
});
Of course you need to setup the change function, which needs to wrap up all the variables required to do the call to Yahoo. Obviously, you'll need to pass in the stock parameter and once you've received the json back from Yahoo you'll need to call your draw function. So borrowing from your code something like this should work:
function change(stock) {
var url = 'http://query.yahooapis.com/v1/public/yql';
var startDate = '2013-09-06';
var endDate = '2014-03-06';
// NB the inclusion of the stock parameter
var req = encodeURIComponent('select * from yahoo.finance.historicaldata where symbol in ("' + stock + '") and startDate = "' + startDate + '" and endDate = "' + endDate + '"');
var data = $.getJSON(url, 'q=' + req + "&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json", draw);
}
You'd have to call the draw function on load otherwise you'll end up with a blank screen and also sort out transitioning from one data set to the next.

Related

Init value on fill option for a select JQuery on first load

Since my previous questions I learned and progressed a lot (this all started from HTML code in println inside a Java file !)
I'm close to my target.
I've got 2 dropdown : dd1 and dd2
I got a java to get values in database
dd1 is an independant list
dd2 options depend of the choice in dd1
Using gson/jquery it works perfectly
My issue is the initialisation of the page.
I load the dd1 using my fillOption function and by default my page display the first value as selected.
So I want that dd2 initialised with this value but when I trigger the change() on dd1 this.value is empty and I don't get why.
$(document).ready(function() {
fillOptions('dd1', this); // Init the first dropdown with my values, works fine
$('#dd1 option:eq(1)').prop('selected', true); // Here I tried to force the selection of the first item, doesn't change anything
// Delcaration of the change function for the first dropwdown
$('#dd1').on('change', function() {
alert(this.value); // display blank on the page load, display the value if I select manually afterwards
fillOptions('dd2', this); // at load, 'this' is blank so nothing is loaded for dd2. Works fine if selected manually. I expected to have the value displayed on screen here.
});
$('#dd1').trigger('change');
});
function fillOptions(ddId, callingElement) {
var dd = $('#' + ddId);
$.getJSON('${pageContext.request.contextPath}/optionsSousType?dd=' + ddId + '&val=' + $(callingElement).val(), function(opts) {
$('>option', dd).remove(); // Clean old options first.
if (opts) {
$.each(opts, function(key, value) {
dd.append($('<option/>').val(key).text(value));
});
} else {
dd.append($('<option/>').text("Choisir parent"));
}
});
}
I also tried getting the value using :
$('#colonne').on('change', function() {
var col = $('#colonne').find(":selected").text();
alert(col);
fillOptions('libelle', col);
});
Same result, col is blank. I'm pretty sure it's simple but I couldn't find an answer. Thanks for your help

How to get the page of an item of Kendo Grid using ServerOperation

I'm trying to retrieve the page index of a selected object of the grid that is using ServerOperation, but I don't know how would I do that without too much complication.
Currently, I'm receiving an Id from the URL (https://...?ObjectId=12) and I will select this item in the grid, but first I have to show the page it is, so I'm trying to get the page number of this row.
The problem is that I'm using ServerOperation(true). In addition, I'm retrieving the paged list without any filters.
function _displayDetailsModal(id, selectRow = true, focusSelected = true) {
$(document).ready(() => {
var url = `${urls.Details}/${id}`;
if (selectRow) {
// GET PAGE OF ITEM THEN
// CHANGE TO PAGE THEN
kendoGrid.selectById(id);
}
if (focusSelected) {
kendoGrid.focusSelected(); // Scrolls to selected row.
}
loadModal(url);
});
}
Is this the kind of thing you are after?
Dojo: https://dojo.telerik.com/iNEViDIm/2
I have provided a simple input field where you can set the page number and then a button which will change the page to the selected page for you.
All I am doing is setting the datasource's page via the page method and then it will go off and make a read to the remote datasource for you and then return that page of data.
$('#btnPage').on('click',function(e){
var page = $('#pageNumber').val();
$('#pageLabel').html('Page Selected Is: ' + page);
var ds = $('#grid').data('kendoGrid').dataSource;
ds.page(parseInt(page));
});
If you select a page higher than the last available then it will just show the last page.
More info can be seen here: https://docs.telerik.com/kendo-ui/api/javascript/data/datasource/methods/page
If you need any further info let me know:
I ended up doing it on the server. That is how I did it:
Controller.cs
Instead of sending just the usual ToDataSourceResult, I add two fiels (PageIndex and ObjectId), and send it to the front-end to change the page and select the row.
[HttpPost("List")]
public IActionResult List([DataSourceRequest] DataSourceRequest request, RequestActionViewModel requestAction)
{
// Getting the pageIndex of the ObjectId present in requestAction.
var objectIndex = elementList.FindIndex(el => el.Id == requestAction.ObjectId) + 1;
var objectPageIndex = Math.Ceiling((decimal)objectIndex / request.PageSize);
var dataSourceResult = elementList.ToDataSourceResult(request);
return Json(new {
Data = dataSourceResult.Data,
Total = dataSourceResult.Total,
AggregateResults = dataSourceResult.AggregateResults,
Errors = dataSourceResult.Errors,
// Extra fields
PageIndex = objectPageIndex,
ObjectId = requestAction.ObjectId
});
}
index.js
I Get from the server the page and the id of the element, select the change the page of the grid, and select the element.
function onGridRequestEnd(e) {
this.unbind("requestEnd", onGridRequestEnd);
if (e.PageIndex) {
kendoGrid.bind("dataBound", function temp() {
// Custom method.
kendoGrid.selectById(e.ObjectId, e.PageIndex);
// To avoid looping.
kendoGrid.unbind("dataBound", temp);
});
}
}

How to update data table on data change highcharts

I have a pie chart that I'm updating dynamically on button click using the code below.
On Button click
$("#myChart").highcharts().series[0].setData($.extend(true, [], data1))
I'm using keys to populate the data table.
keys: ['Count','Value'],
This works fine and updates the chart but I also have export data table enabled in export menu but that data table doesn't update. It remains the same on all successive button clicks.
How can I update the data table with button click to show data for new data.
here is a fiddle but it doesn't really use buttons but just to give you an idea of my chart : https://jsfiddle.net/mewohraz/1/
Update: The solution below works but I had to comment out this piece of code that I'm using to toggle the viewData table. It allows me to close the table if you click on viewData again. How do I get to work it with chart.viewData()?
Highcharts.Chart.prototype.viewData = function () {
if (!this.insertedTable) {
var div = document.createElement('div');
div.className = 'highcharts-data-table';
// Insert after the chart container
this.renderTo.parentNode.insertBefore(div, this.renderTo.nextSibling);
div.innerHTML = this.getTable();
this.insertedTable = true;
div.id = this.container.id + '-data-table';
}
else {
$('#' + this.container.id + '-data-table').toggle();
}
};
You need to call viewData internal method to refresh the data table:
$('#update').on('click', function() {
var data1 = [...];
chart.series[0].setData(data1);
chart.viewData();
});
Live demo: https://jsfiddle.net/BlackLabel/ahowu9tm/

Update/Refresh Listbox based on Dropdown selection with trigger("chosen:updated")

I have a Listbox that I need refreshed after a user selects an option in DropdownList.
Image is self explanatory. If one selects Department -> load list of departmetns in Listbox, if one selects Vat Rate refresh/load list of vat rates into the listbox below. (Default department list is loaded on page load). I am currently attempting this with trigger("chosen:updated") and having no luck refreshing listbox. Here is my code for that functionality.
$(function () {
$("#SelectFilter").change(function () {
if (document.getElementById('SelectFilter').value == 1) //dropdownlist
{
//empty listbox
$('#SelectItems').empty();
//append new list to listbox
$.each(data.Departments, function (index, element) {
$('#SelectItems').append('<option value="' + element.Value + '">'
+ element.Text + '</option>');
});
//refresh
$('#SelectItems').trigger("chosen:updated");
}
if (document.getElementById('SelectFilter').value == 2)
{
$('#SelectItems').empty();
$.each(data.VatRates, function (index, element) {
$('#SelectItems').append('<option value="' + element.Value + '">'
+ element.Text + '</option>');
});
$('#SelectItems').trigger("chosen:updated");
}
});
});
Recognising the selected value from the dropdownlist isnt an issue, that works fine. Listbox is currently not getting updated/refresh with new selection. And I cannot figure out were I am going wrong with this.
Try to put all your code for creating the list into a function, and then bind an event on chosing one of the selected items to call this function which generates a new list instead of using .trigger(). If you provide the HTML part as well, I'll post example code soon.
It's not clear to me if you have a problem with recognizing the selected value, or with populating the secondary select tag, or with the initial loading of the data. So I am providing an example of the three steps.
First, to detect the selected value, you need to provide a .change() handler and extract the selected value with .val(). Something similar to this:
$("#SelectFilter").change( function() {
var v = $(this).val();
if (v=="value1") {
} else if (v=="value2") {
} else {
}
});
then each of the changes detected has to refresh the contents of the secondary select tag, something as simple as this...
$("#SelectItems").empty();
['first item','second item','troisième'].forEach( (v,i) =>
$("#SelectItems").append($("<option>").val("item"+i).text(v))
);
}
And finally triggering the initial load should be as simple as triggering a change event
$("#SelectFilter").change();
I have put all the steps together in this fiddle https://jsfiddle.net/mud9u8yL/6/

jQuery - remove li from array with delete image

I'm attempting to make a menu bar that can have <li> elements added and removed. So far so good, but when I try and remove them I'm running into issues. I've toyed with this for a couple hours and now I'm wondering if this whole process could just be made easier (maybe an object?).
Anyways, here's the full code (80 lines), with comments to follow along.
var tabs = $('.accountSelectNav');
var titles = [];
var listItems = [];
// when the page loads check if tabs need to be added to the ul (menu bar)
$(document).ready(function(e) {
if ($.cookie('listItems') != null) {
console.log('not null');
//return "listItems" to it's array form.
listItems = JSON.parse($.cookie('listItems'));
$('.accountSelectNav').append(listItems);
}
});
$('.selectTable td:first-child').on('click', function(e) {
$('#home_select').removeClass('navHighlight');
//grab the text value of this cell
title = $(this).text();
$.ajax({
url:'core/functions/getAccountId.php',
type: 'post',
data: {'title' : title}
}).fail (function() {
alert('error');
}).done(function(data) {
accountId = $.trim(data);
// store values in the cookie
$.cookie('account_id', accountId, {expires : 7});
$.cookie('title', title, {expires : 7});
window.location = ('home_table.php');
});
// make sure the value is NOT currently in the array. Then add it
var found = jQuery.inArray(title, titles);
if (found == -1) {
titles.push(title);
addTab();
}
// make sure the value is NOT currently in the array. Then add it
found = jQuery.inArray(title, listItems);
if (found == -1) {
addListItem();
//place <li>'s in cookie so they may be used on multiple pages
$.cookie('listItems', JSON.stringify(listItems));
};
});
$("body").on("click", ".deleteImage", function (e) {
var removeTitle = $(this).closest('li').find('a').text();
var removeItem = $(this).closest('li')[0].outerHTML;
//remove title from "titles" array
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
//remove <li> from "listItems" array
listItems = jQuery.grep(listItems, function (value) {
return value != removeItem;
});
// this shows the <li> is still in the listItemsarray
console.log(listItems);
// put the array back in the cookie
$.cookie('listItems', JSON.stringify(listItems));
removeTab(this);
});
$("body").on("mouseover", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').show();
});
$("body").on("mouseleave", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').hide();
});
function addTab() {
tabs.append('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
};
function removeTab(del) {
$(del).closest('li').remove();
}
function addListItem() {
var s = ('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
listItems.push(s);
}
So you see I have two arrays of equal length that should always be the same length. One stores the title to be displayed in the tab, the other holds the html for the <li> which will be appended to the <ul>. I have no problem removing the title from its array. However removing the <li> from it's array is becoming a rather big hassle. You see when I get the <li> element after its been inflated the html inside does not exactly match what was put in, the browser adds style elements.
Example, the variable "removeItem" represents the html value of the selected <li> I wish to remove. It looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage" style="display: inline;"></li>
yet the value in my array "listItems" looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage"/></li>
So my attempt at removing it from my array always fails because they aren't a perfect match.
Now my question is how do I remove this <li> item? Also is there an easier way to do this whole process and I'm just not seeing it?
Thanks for your time.
EDIT
Fiddle by request here
Easiest way I can explain it.
Click the link to the fiddle.
Click any cell in the "App Name" column
This will add a <li> to the <ul> (menu) above of the table
When you hover over the <li> a picture appears
Click the picture
This should remove the <li>, both from the <ul> and from the array listItems
right now it does not
In the process of making this easier to check, I've taken your JSFiddle and did the following:
removed extra console.log and comments
removed interaction with cookies (since I did not have them in the first place, I figured they wouldn't just the first scenario)
After doing so I reached a point (you can see it here) where the desired functionality just works.
I even went ahead and removed the ajax stuff because that alert was driving me crazy. (here)
Since this works fine, my guess is that your issue lies between the lines that I removed.
Your usage of cookies is as follows:
To load existing tabs and add them back again
To save account_id and title, which is not used back again
To persist the listItems after a new item has been added
I then opened up the console with your version of the fiddle and the execution of javascript stops at $.cookie() with the error undefined is not a function.
This clearly indicates that the issue present in the Fiddle is that jQuery.cookie is not present and so those calls are halting the execution of the rest of your script. This also explains why it just started working when I took them out.
I posted the whole process of how I got there to indicate how I trimmed down the problem to specific parts, which is useful to reduce the problem space. When you're out of options and reach a place when you're lost, it's easier to post a question with less code and the specific part of the problem that you've identified. This will help you in finding the issues that you're facing and StackOverflow to provide proper answers to your questions.
Hope it helps!
Here is the solution I came up with. It should be much easier for people to understand than my original post. Although it's a long read it may be worth it, especially for new developers.
The point of this code is to make a menu bar out of an un-ordered list or <ul>. The menu bar needs to be used on multiple pages. So I'll be using cookies.
I start with this code to get a text value from my table.:
$('.selectTable td:first-child').on('click', function(e) {
// This value will be used later for the name of the tab or `<li>` inside our menu bar or `<ul>`
title = $(this).text();
});
Then I place the value in an array. I do this only if the array does not already have this string inside it. I do not want duplicates:
var found = jQuery.inArray(title, titles);
var titles = [];
if (found == -1) {
titles.push(title);
}
Then I store the array into a cookie, using a library like this:
$.cookie('titles', JSON.stringify(titles));
Now when any page loads that needs this menu bar I run this code to check if there are any values:
$(document).ready(function() {
if ($.cookie('titles') != null) {
titles = JSON.parse($.cookie('titles'));
}
});
Now I need to loop through the array. When I loop through the array I have to do 3 things:
1) Grab the string value.
2) Add the html to my new string so it becomes a list item or <li>.
3) Append the newly created <li> to our <ul>.
Like so:
for(var i = 0; i < titles.length; i++) {
var str = titles[i];
var listItem = '<li class="navHighlight">'
+ '<a href="#">'
+ str
+ '</a>'
+ '<a href="#">'
+ '<img src="images/delete.png" class="deleteImage"/>'
+ '</a>'
+ '</li>';
$('.accountSelectNav').append(listItem);
}
Now, if I want to remove this <li> I click the delete image found inside our <li>. What delete image you say? Look at the html I added again. You will see I add an <img> tag in there.
Now delete like so:
$("body").on("click", ".deleteImage", function (e) {
// grabs the text value of my li, which I want to remove
var removeTitle = $(this).closest('li').find('a').text();
// runs through my titles array and returns an array without the value above
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
});
Then I simply place the new array inside my cookie once again. Like this:
$.cookie('titles', JSON.stringify(titles));
And finally I remove the tab like this:
removeTab(this);
function removeTab(del) {
$(del).closest('li').remove();
}
Yay, I'm done. So now, if anyone has a more elegant way of accomplishing this I'm listening. I have no doubt there's a better way, javascript/jQuery isn't even close to my strong point.
The full code can be found here.

Categories

Resources