User input to create D3 pie chart - javascript

I'm trying the create a pie chart using d3pie.js user input values. Below is my code that is functional but takes random numbers on button click.
But I wan't the new segment value to be taken from user input field. I tried assigning the jquery function to a variable and then assigning that variable to value like below but that didn't work. I also tried to directly define the Jquery function to define value.
Attempt 1 (Didn't work):
var a = $("#first").val();
var num = 4;
$("#addData").on("click", function() {
adata.push({
label: num.toString(),
value: a
});
pie.updateProp("data.content", adata);
num++;
Attempt 2 (Didn't work):
adata.push({
label: num.toString(),
value: $("#first").val()
});
Below is my working code, would really appreciate some inputs from the folks on this.
var adata = [
{
"label": "JavaScript",
"value": 5,
},
{
"label": "Ruby",
"value": 3,
},
{
"label": "Java",
"value": 2,
}
];
--------------------
"data": {
"sortOrder": "value-desc",
"content": adata
--------------------
var num = 4;
$("#addData").on("click", function() {
adata.push({
label: num.toString(),
value: Math.floor(Math.random() * 10) + 1
});
pie.updateProp("data.content", adata);
num++;
--------------------
<input type="text" class="form-control" id="first">
<button type="button" class="btn btn-default" id="addData">Add Value</button>

Problem is because you are passing a string in value, it expects a number.
in your code
adata.push({
label: num.toString(),
value: a //incorrect it has to be a number.
});
need to do
adata.push({
label: num.toString(),
value: +$("#first").val() //make it a number so + is appended.
});
working code here

Related

Best way to filter results based on range slider range of values?

I have a range slider that filters JavaScript objects based on their output key:
<input id="outputSlider" class="form-control" type="range" min="4" max="10">
Here's a small example of an object: (there are 50 of them)
const stratPickups = {
"Model 1": {
name: "Model 1",
design: "single-coil",
output: 4,
tone: 3,
},
"Model 2": {
name: "Model 2",
design: "single-coil",
output: 5,
tone: 5,
},
"Model 3": {
name: "Model 3",
design: "single-coil",
output: 6,
tone: 6,
},
}
On the input of the slider, it calls this function here:
const outputSliderFunction = () => {
const slider = document.querySelector("#outputSlider");
let sliderValue = Number(slider.value);
activeFilters.output = sliderValue; //Pushes the slider value into an object called activeFilters
const filteredData = performFilter(data, activeFilters);
refreshView(filteredData); //Displays the "cards" with the product information
};
Right now, this is working, but I want to improve it. The way it works now, if the sliderValue matches the output, the card gets displayed on the page. However, there are big chunks of the slider range that don't show any results. I want to change the function to accept a range of inputs, but I wasn't sure how and am looking for ideas.
I thought I could change the objects to have a min-output and max-output and figure out how to show the results when the slider value is between them, but I'm not sure how I can do that.
Any ideas?
Here's the performFilter function:
const performFilter = (data, activeFilters) => {
let result = data;
Object.keys(activeFilters).forEach((key) => {
result = result.filter((d) => d[key] === activeFilters[key]);
});
return result;
};

Retrieve the value of a nested object that has a changing name with Javascript

I am having trouble trying to get a value from a list of objects in a Woocommerce webhook. Woocommerce inputs the order number of the selected dropdown (ie.Royal Mail is 5th in the dropdown, USPS is 3rd) so I need to be able to access this when it is any value.
var labelchoice = event.line_items[0].meta_data[1].value[0].label; // SUCCESS This returns "Custom"
var labelchoice1 = event.line_items[0].meta_data[1].value[0].value[0].value.5.value; // FAILED with "Unexpected Number"
var labelchoice2 = event.line_items[0].meta_data[1].value[0].value.value.5.value; // FAILED with "Unexpected Number"
var labelchoice3 = event.line_items[0].meta_data[1].value[0].value[0].value[0].5.value; // FAILED with "Unexpected Number"
var labelchoice4 = event.line_items[0].meta_data[1].value[0].value[0].value[0].5[0].value; // FAILED with "Unexpected Number"
The number "5" that is referenced is the number of the dropdown option (there are 8 options eg. USPS, Airmail etc) on a product page. The problem here is I don't know what the number is going to be selected (the dropdown the customer chooses) so that "5" object needs to be perhaps referenced as a wildcard as it could be any number from 1-8.
Can anyone help me grab that nested "label" value? - shown in the example as "Royal Mail"
"meta_data": [
{
"id": 166,
"key": "Dropdown options",
"value": "Custom"
},
{
"id": 167,
"key": "_WCPA_order_meta_data",
"value": [
{
"type": "select",
"name": "select-1549626172813",
"label": "Custom",
"value": {
"5": {
"i": 5,
"value": "UK-RM",
"label": "Royal Mail"
}
},
In case the property name (5) is not known, it can be queried:
var labelchoiceX = event.line_items[0].meta_data[1].value[0].value[
Object.keys(event.line_items[0].meta_data[1].value[0].value)[0]
].label;
You can pass the index as a string variable
const index = '5' // or any other value from the select dropdown
const labelchoice = event.line_items[0].meta_data[1].value[0].value[index].label
Here's in action: https://codepen.io/herodrigues/pen/RvYqeL
You are after the [] property access syntax.
const m = new Map();
for (let i = 1; i <= 8; i++) {
m.set(i,
event.line_items[0].meta_data[1].value[0].value[String(i)].value /* or .label? */);
}
Try this. I think this is the correct order:
var labelchoice = event.line_items[0].meta_data[1].value[0].value.5.label;

$watch how to get the which value has been changed in the array?

I am new to angularjs. In this snippet I have an array which is like -
$scope.jsonData = [{
annotationType: "Full Name:"
endOffset: "17"
startOffset: "0"
type: "FullName"
value: "A"
},
{
annotationType: "Email:"
endOffset: "188"
startOffset: "133"
type: "FullName"
value: "B"
}
]
Now, Here I am using a watch.
$scope.$watch('jsonData', function(newVal, oldVal) {
console.log("Value changed==>", newVal);
}, true);
Now with this, my jsonData may get updated frequently, It may get added an element or remove. So, I from this watch How will I get to know which element has been added or which has been deleted or which elements value has been updated? And also if new value is added then what is that value or index of that value?
Thanks in advance.
I'm not sure, but you can do something like that :
newObjects = newVal.filter(new => !oldVal.some(new => JSON.stringify(new) == JSON.stringify(old)) )
removedObjects = oldVal.filter(old => !newVal.some(new => JSON.stringify(new) == JSON.stringify(old)) )
If annotationType is unique then this the way to get the added or removed elements in your jsonData array.
var app = angular.module('app', [])
app.controller('ctrl', function($scope){
$scope.jsonData = [{
annotationType: "Full Name:",
endOffset: "17",
startOffset: "0",
type: "FullName",
value: "A"
},
{
annotationType: "Email:",
endOffset: "188",
startOffset: "133",
type: "FullName",
value: "B"
}
]
var i = 0;
$scope.addInArray = function(){
i++;
$scope.jsonData.push({
annotationType: "Yo:"+i,
endOffset: "17",
startOffset: "0",
type: "Yo",
value: "Yo"
})
}
$scope.removeFromArray = function(){
$scope.jsonData.pop()
}
$scope.$watch('jsonData', function(newVal, oldVal) {
if(newVal.length > oldVal.length){
var values = oldVal.map(e=>e.annotationType)
//an object has been added
var changed = newVal.filter(function(obj){
return !(values.includes(obj.annotationType)); });
console.log("Added object is ",changed[0])
}
if(newVal.length < oldVal.length){
var values = newVal.map(e=>e.annotationType)
//an object has been removed
var changed = oldVal.filter(function(obj){
return !(values.includes(obj.annotationType)); });
console.log("removed object is ",changed[0])
}
}, true);
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<button ng-click="addInArray()">Add</button>
<button ng-click="removeFromArray()">Remove</button>
</div>
When you use $scope.$watch you're only verifying if the value changed(in case it's a primitive variable) or if the reference changed (in case the watched variable is a referece variable (like arrays and objects).
If you want to watch for changes in the array, use $watchCollection.
If you want to watch for changes in the elements of the array, use $watch passing the last parameter as 'true'.
Note that it all affects the performance of the app. Being the watch by value the least performatic, and the watch by reference the most performatic.
All this can be seen in the following image:

handlebars + json to show output partially (split json data? )

Here is my code http://jsfiddle.net/5kkja1ua/
<ul id="results"></ul>
<script type="text/x-handlebars-template" id="item_tmpl">
{{#json}}
<p> {{index}}: {{title}} </p>
{{/json}}
<button>next</button>
</script>
var dataObject = {
json:[
{
"index": 0,
"title": "IMAGEFLOW"
},
{
"index": 1,
"title": "ENERSOL"
},
{
"index": 2,
"title": "BUNGA"
},
{
"index": 3,
"title": "BITENDREX"
},
{
"index": 4,
"title": "MAROPTIC"
},
{
"index": 5,
"title": "AEORA"
},
{
"index": 6,
"title": "PYRAMIA"
},
{
"index": 7,
"title": "ANIXANG"
},
{
"index": 8,
"title": "SNORUS"
}
]
};
var tpl_source = $("#item_tmpl").html();
var h = Handlebars.compile(tpl_source);
var content = h(dataObject);
// output
var results = document.getElementById("results");
results.innerHTML = content;
One method I can do it easily is to get 3 items wrapped (by using slice()) in a div and then hide and show. However, this method needs to load the whole lot first.
I'd like to know if possible to have the output to show every 3 items as a group? if possible to split the json data?
0: IMAGEFLOW
1: ENERSOL
2: BUNGA
then click next to show another 3 items and so on. Thanks
What about to create handlebars helper to use each with suport from/to parameters, like
Handlebars.registerHelper('each_from_to', function(ary, from, max, options) {
from || (from = 0);
var result = [ ];
for(var i = from; i < from + max && i < ary.length; ++i)
result.push(options.fn(ary[i]));
return result.join('');
});
After that your template will looks like
<script type="text/x-handlebars-template" id="item_tmpl">
{{#each_from_to json startFrom rowsOnPage}}
<p> {{index}}: {{title}} </p>
{{/each_from_to}}
</script>
Check this fiddle. Does it solve your problem?
http://jsfiddle.net/5kkja1ua/1/

How to get entries between a price x and y?

im using the current jquery ui slider with a range:
http://jqueryui.com/slider/#range
and the underscore.js
http://underscorejs.org/
so ive a minimum and a max which i send, after the user stopped to slide to a function:
currentSlide:function(){
$('#slider').slider({
range: true,
min: min,
max: max,
values: [ vmin, vmax ],
stop:$.proxy(this.afterSlide,this)
});
},
afterSlide:function(event, ui) {
console.log(ui.values[0]);
},
in the afterSlide function i get the min/max correctly, but i dont know how to use underscore.js to get all entries which have a price starting by this min and end by the max.
Examplearray:
var sample = {
"response": {
"things": [{
"index": 0,
"price": "10"
},{
"index": 1,
"price": "15"
},{
"index": 2,
"price": "60"
},{
"index": 3,
"price": "10"
},{
"index": 4,
"price": "100"
}
]
}
};
After im using the Slider i have the min/max [12,61] so i want to see all entries ONLY starting with a price between 12 and 61 $
var result = _.find(sample.response.things, min/max);??
I dont understand the _.range() function correctly to use it how i need, or to create a correct statement with the .where/.find() function.
I'd just get the max and min values, and since this seems rather trivial I'd just iterate the object and check if the relevant value is within the range, and add it to a new object, no _underscore needed really, something like this:
afterSlide:function(event, ui) {
var min = ui.values[0],
max = ui.values[1],
items = {};
$.each(sample.response.things[0], function(key, val) {
if (val.price > min && val.price < max) {
items[val.index] = val.price;
}
})
},

Categories