Setting default selection of a dropdown menu with D3 - javascript

I created a dropdown menu of some months as options, but wanted to predesignate one option as the default value. However, the default selection seemed to stubbornly remain the first option in the list.
I tried the below code, which made a lot of sense to me because for any other attribute, setting up a simple comparison is sufficient to alter that attribute's value.
var defaultOptionName; // desired default dropdown name
d3.select("#dropdown").append("select")
.on("change", someFunction)
.selectAll("option").data(dataset)
.enter().append("option")
.attr("value", function(d){return d;})
.attr("selected", function(d){
return d === defaultOptionName;
})
.text(function(d){ return d; });
I knew that my problem was just a matter of the right syntax, but when I tried to search the internet and stackoverflow, but couldn't figure out what I was missing.

I found that instead of using .attr, I needed to use .property in order to access the default selection option. A simple substitution was all that was required, so your code snippet would look something like:
.property("selected", function(d){ return d === defaultOptionName; })

Related

Sorting function issue with grouped bar chart

This question is similar to my previous question here, the difference is that the answer to that question doesn't work for my new chart.
Code here: Plunker
The issue is that the sorting toggle checkbox stops sorting the chart when you try to uncheck the box again.
If I remove the function from d3.select("#myCheckbox") and replace it with d3.select("#myCheckbox").on('change', update) it works again, but rather than the bars shifting x position it only shifts the ticks position on the x-axis & the bars update and change position simultaniously.
The problem here is that you're reassigning sortIndex when clicking on the checkbox:
d3.select("#myCheckbox").on('change', function() {
sortIndex = data.map( function(d) { return d.State} );
update();
});
However, the very data it uses has been sorted!
The solution is simple, just remove that:
d3.select("#myCheckbox").on('change', update);
Besides that, make sure you're using the proper key function:
var barGroups = g.selectAll(".layer")
.data(data, function(d){return d.State});
Here is the updated Plunker: https://plnkr.co/edit/goU5K7LB4Gj1jhynLqGt?p=preview

How to unselect a class when clicking on another class with javascript

I have a map of the US with selectable counties that when clicked change their background to red. What I want to happen is when the user clicks on another county it deselects the current county and then selects the new one only. Currently right now when clicking on the county class it changes the class which gives it a background of red, but when you click another county then both are red.
Here is the code where I draw the map and change classes when clicked:
//DRAW MAP
d3.json("js/map.json", function(error, mapData){
if (error) throw error;
//draw counties
edit.map.append("g")
.selectAll("path")
.data(topojson.feature(mapData, mapData.objects.counties).features)
.enter().append("path")
.attr("class", "counties")
.attr("d", edit.path)
.on("click", function(d){
sFips = d.properties.STATEFP;
cFips = d.properties.COUNTYFP;
//display values in text boxes
$("#locationCountySelect").val(cFips);
$("#locationStateSelect").val(sFips);
//change clicked county class name
if (this.className.baseVal == "counties") {
this.className.baseVal = "selectedCounty";
//send new county to db
} else {
this.className.baseVal = "counties";
}
});
});
Again, how can I only have one county selected at a time?
For this purpose I suggest you ditch jQuery in favor of D3. The following two lines in your click listener will do the job:
d3.select(".selectedCounty").attr("class", "counties");
d3.select(this).attr("class", "selectedCounty");
The first statement selects the element having class .selectedCounty and sets the class attribute to counties instead. The second one selects the element clicked upon and set its class to selectedCounty.
It might also be worth considering to keep a reference to the currently selected element in a variable in the outer scope to not having to reselect on every click:
var selectedCounty = d3.select(".selectedCounty");
edit.map.append("g")
// ...
.on("click", function(d) {
selectedCounty.attr("class", "counties");
selectedCounty = d3.select(this).attr("class", "selectedCounty");
}
As requested by Teton-Coder's comment there might be the need to toggle the class instead of just replacing it. Using selection.attr("class", "selectedCounty") will set the value of the class attribute, whereby replacing any other classes set on the element. Although you are allowed to pass a space-separated list to the attribute via this function the easiest way to toggle a specific class on an element is the use of selection.classed(). The second argument to that function is a boolean value determining if the class should either be assigned to the element or be removed from it while leaving all other classes intact. The above code can thus be rewritten as:
var selectedCounty = d3.select(".selectedCounty");
edit.map.append("g")
// ...
.on("click", function(d) {
selectedCounty.classed("selectedCounty", false);
selectedCounty = d3.select(this).classed("selectedCounty", true);
}

Access Selected Date from dynamically created Calendar Control asp/javascript/VB.net

UPDATE: To anyone who still may read this, I used a completely different way of doing this. With AjaxToolkit's Calendar Extender, I was able to easily add a calendar dynamically and use Javascript to change the format of different date inputs so that calendar extender could read it. Highly recommend you go the AjaxToolkit route if you are trying to do something similar to me.
I have dynamically created a Calendar control(asp:Calendar), Buttons, and dropdown lists for a Comment Class. The Comment Class will always have a textbox in it, but if the ID/attribute label of the textbox is DOB or birthday or something similar, these other controls get dynamically created.
So far, the calendar, dropdown lists, and one of the buttons works, but I am have trouble with the last button. Currently, I dynamically add a script that is used for one of the buttons to show and hide the div that contains that Calendar, dropdown lists, and relevant buttons, which works amazingly. I am trying to add another script trigger on a button press to take the selected date from the Calendar and put it in the textbox.
Right now, I am just trying to get access to the Calendar. I am using code that looks like this:
function use_calendarDate(){
var calendarDate = '<%=question128_Cal1.SelectedDate%>';
alert(calendarDate);
}
I found this function in another question similar to this, but instead of getting the date, it just puts <%=question128_Cal1.SelectedDate%> as a string into the alert box.
This LINK shows exactly what I am trying to do, but I get a different result. Can anyone help me with what I am doing wrong here?
Interestingly, when I use
var calendarDate = question128_Cal1.SelectedDate;
OR
var calendarDate = question128_Cal1.value;
My alert box tells me undefined.
Thanks in advance.
In case it is needed, my calendar control is created like this:
In Page_Init
Dim calendar1 As New Calendar
Call BuildCalendar(calendar1)
calendarDiv.Controls.Add(calendar1)
Here is the function referenced above.
Private Sub BuildCalendar(ByRef calendar1 As Calendar)
calendar1.ID = "Cal1"
calendar1.SelectedDate = DateTime.Today
calendar1.Attributes.Add("runat", "server")
calendar1.Attributes.Add("OnClientDateChanged", "onDateChange")
calendar1.Attributes.Add("borderwidth", "2px")
calendar1.Attributes.Add("BackColor", "White")
calendar1.Attributes.Add("width", "200px")
calendar1.Attributes.Add("ForeColor", "Black")
calendar1.Attributes.Add("Height", "180px")
calendar1.Attributes.Add("Font-Size", "8pt")
calendar1.Attributes.Add("Font-Names", "Verdana")
calendar1.Attributes.Add("BorderColor", "#999999")
calendar1.Attributes.Add("BorderStyle", "Outset")
calendar1.Attributes.Add("DayNameFormat", "FirstLetter")
calendar1.Attributes.Add("CellPadding", "4")
calendar1.Attributes.Add("ShowNextPrevMonth", "True")
calendar1.Attributes.Add("SelectionMode", "Day")
calendar1.Attributes.Add("ShowTitle", "false")
calendar1.Attributes.Add("OnSelectionChanged", "Calendar_SelectionChanged")
calendar1.TodayDayStyle.ForeColor = Drawing.Color.Black
calendar1.Attributes.Add("todaydaystyle-backcolor", "#cccccc")
calendar1.Attributes.Add("selectorstyle-backcolor", "#cccccc")
calendar1.NextPrevStyle.VerticalAlign = VerticalAlign.Bottom
calendar1.Attributes.Add("dayheaderstyle-font-size", "7pt")
calendar1.Attributes.Add("dayheaderstyle-font-bold", "true")
calendar1.Attributes.Add("dayheaderstyle-backcolor", "#cccccc")
calendar1.Attributes.Add("selecteddaystyle-font-bold", "true")
calendar1.Attributes.Add("selecteddaystyle-forecolor", "White")
calendar1.Attributes.Add("selecteddaystyle-backcolor", "#666666")
calendar1.Attributes.Add("titlestyle-font-bold", "true")
calendar1.TitleStyle.BorderColor = Drawing.Color.Black
calendar1.Attributes.Add("titlestyle-backcolor", "#999999")
calendar1.Attributes.Add("weekenddaystyle-backcolor", "#ffffcc")
calendar1.OtherMonthDayStyle.BackColor = Drawing.Color.Gray
End Sub
Is it question128_Cal1 or question128_Calendar1 ? Your function use_calendarDate() refers to the first. Typo ?
Interestingly, when I use
var calendarDate = question128_Calendar1.SelectedDate;
OR
var calendarDate = question128_Calendar1.value;
My alert box tells me undefined.
That's because the client script has no knowledge of what 'question128_Calendar1' is. That is a server-side ID.
Is there a reason why you can't use markup to define the calendar instead that rather large 'BuildCalendar' function? You're making a bit of a maintenance nightmare by doing that, IMO.

Dynamically change color of D3 Node (force directed graph)

I'm trying to change the color of a node with a specific ID in D3, depending on what the user selects in a survey. I have this line of code:
$("#" + type).find("path, circle").attr("fill", "#333333");
where "type" is the name of the node I want to target (this name could change depending on the survey options selected, obviously). Looking at the console, the correct node is selected, but I just can't change the color. I've also tried .style("fill","#333333") instead of .attr("fill", #333333), but nothing seems to work!
the d3 way is this:
d3.select("#" + type).select("circle").style("fill", "#333333");

D3 elements being removed although I'm only adding new ones

It's been a while since I picked up d3.js and it seems I'm a bit rusty. I'm trying to do a form where I can add more input fields by clicking + and removing the existing ones by clicking -.
To try and discover what I had wrong, I started colouring the enter(), update and exit() with green, yellow and red respectively.
The original data array has two elements, so they show up as green:
Then I click on the plus sign which pushes a new element to the array, and I expected to see two yellows and one green, but instead I see all the elements deleted besides the last one, and this repeats if I click + again:
And plus again:
I've compared my code with the classic General Update Pattern and I can't see anything significant apart from the way I set the keys, in which I use the e-mail. This is code I've added to fix another underlying issue where not all the boxes were being added, just one out of each 3.
My commented code is as follows:
var renderFriends = function () {
console.log("Rendering friends:" + friendsList)
var friends = d3.select('.friends-container')
.selectAll('div')
.data(friendsList, function(d,i) {
// this was something I added when I thought the problem were the keys
return d
})
// updates will be yellow
friends.classed("update", true)
var enter = friends.enter()
// Friend box
// all the divs are because I'm using foundation css
// the new class is what marks the font green
var friendBox = enter.append('div').classed('large-12 columns new', true)
friendBox.append('div').classed('large-8 columns', true)
.append("input")
.attr("type", "text")
.attr("value", String)
// Icon box
var iconBox = friendBox.append('div').classed('large-2 left columns', true)
.append("i")
.classed('fi-minus', true)
.on("click", function(d) {
// out of scope for this question
console.log("Removing:" + d)
friendsList.remove(friendsList.indexOf(d))
renderFriends()
})
// exit state should colour the fonts red
friends.exit().classed('remove', true)
}
I did a small test with custom styles and this is what got (when I clicked minus button):
All elements have green background since they all have "new" class, the "update" elements have yellow border, and the "remove" red background.
So what I've noticed is that you have a various Divs nested, and the problem is that when you do a selectAll('div') is going to select all divs and d3 is expecting for each div element being selected to be a data element corresponding to it.
So if you want to add another element and your friendsList is:
friendsList = ['a#test.com','b#test.com','c#test.com'];
d3.selectAll('div') is going to take 6 divs (when you had 2 friends and added one), and its going to bind only 3 elements because your dataset contains only 3 friends, and its going to target the rest of elements as "exiting".
To solve this, simply change your select using a class like '.friend' and also add it to each element being inserted (only the main container div);
Like this:
http://jsfiddle.net/2codv59e/

Categories