How to dynamically check the fields and create array? - javascript

In my angular app, i am building a pivot table using pivot.js, which works prett well.
I need to load all the indexes from elastic search, when the user changes the index, it has to load the corresponding data to the pivot table. This i have achieved with the following code.
Now my issue is whenever user changes the index, i make a service call to get the fields of the table and the complete data of the table. I need to dynamically build an array for the pivot table.
Here is a sample, i have a product table with the fields and data corresponding.
I need to dynamically map the fields and obtain the data to be bind.
//assume these are the fields of a table i get from the service
$scope.ProductFields = ['Name','Code','UOM'];
//assume this is the data i get from the rest service
$scope.ProductData = [
{
Name: "ProductA",
Code: "#f00",
UOM:"Units"
},
{
Name: "ProductB",
Code: "#0f0",
UOM:"Units"
}
// how can i build a dynamic object of product from the above data with the fields
//something like this
//for(dataItem in ProductData)
// {
// for(x in ProductFields)
// {
// $scope.datatobeBuild.push({fields[x]:data[dataItem]});
// }
// }
// $scope.products=$scope.datatobeBuild;
];
Here is the complete Code

You can build the objects using nest loops:
$scope.products = [];
for (var i = 0; i < $scope.ProductData.length; i++) {
var data = $scope.ProductData[i],
product = {};
for (var j = 0; j < $scope.ProductFields.length; j++) {
var field = $scope.ProductFields[j];
product[field] = data[field];
}
$scope.products.push(product);
}
or
$scope.products = [];
$scope.ProductData.forEach(function(data) {
var product = {};
$scope.ProductFields.forEach(function(field) {
product[field] = data[field];
});
$scope.product.push(product);
});

You need to construct object with dynamic keys. You can don it like this using bracket notation:
$scope.ProductData.forEach(function(data) {
$scope.ProductFields.forEach(function(field) {
var dataItem = {};
dataItem[field] = data;
$scope.datatobeBuild.push(dataItem);
});
});

Related

Use data (Json), create new element, row and columns for each object in array

I'm new at JavaScript.
We are supposed to get data from here: https://stryk.herokuapp.com/tipset
then use the data, creating a new row (tr) with columns (td) for each game (I can't change anything in the HTML file). It supposes to look something like this https://i.stack.imgur.com/3ejGx.png
I can't figure out how to loop through the data and then use it.
import {getData} from './getdata.js';
let data = getData();
event();
function createTR(text) {
var x = document.createElement("TR");
x.setAttribute("class", "myTr");
document.getElementById("table").appendChild(x);
var y = document.createElement("TD");
var t = document.createTextNode(text);
y.appendChild(t);
document.querySelector(".myTr").appendChild(y);
}
function event() {
document.querySelector('#active').addEventListener('click', myFunction);
}
function myFunction() {
data.then(createTR);
}
export function getData() {
return fetch('https://stryk.herokuapp.com/tipset')
.then(function (response) {
return response.json();
})
.then(function (data) {
console.dir(data);
});
}
Am I right in understanding that your question is: I have some JSON data with multiple elements. How do I traverse those elements in javascript? If that is correct, you need three steps.
First convert the JSON to an object
var dataobj = JSON_parse(data)
then you can get an array of the keys in the object
var datakeys = Object.keys(dataobj)
then you traverse the obj using a for loop
for (var i = 0; i < datakeys.length; i++) {
var dataval = dataobj[datakeys[i]]
// make your new row with the data
}

How to loop on local storage objects in array or convert data in JSON

I am building ATM project and storing user data in local storage but after then I collect data and loop on this to match an existing user or creating a new user the data I can get is not be able to convert on JSON
after getting data from local storage I can't be able to convert to JSON for looping the data.
function User(id,pin,amount) {
this.id = id,
this.pin = pin,
this.amount = amount
}
var memory = [];
function loginSignup(){
var id= document.querySelector('.card').value;
var pin= document.querySelector('.pass').value;
var user = new User(id,pin);
user = JSON.stringify(user);
memory.push(user);
localStorage.setItem('user', memory);
var localData = [];
localData.push(localStorage.getItem('user'));
console.log(localData);
}
for(var i=0; i<localstorage.length; i++){
if(localstorage[i].id == id){
only allow update }
else{ update new user}
Like this is for understanding I want to loop in local storage data that users enter.
You need to use JSON.stringify while saving user data into storage:
localStorage.setItem('user', JSON.stringify(memory));
Now, whenever you need you can get the array back which will be parseable and traverseable:
var data = window.localStorage.getItem('user');
if (data) {
data = JSON.parse(data);
for (var i=0; i< data.length; i++) {
if (JSON.parse(data[i]).id == id) { // see note below
console.log("matched user", data[i])
}
else {
console.log("other user:", data[i])
}
}
}
Note; down the tree you also need to parse user-data array elements eg. JSON.parse(data[i]) because you have stringified that before pushing into memory array.
DEMO https://jsfiddle.net/pg2bsLve/1/

Tableau JS Filter: Pass filters from one dashboard to all others

I am relatively new to JavaScript and the Tableau JS API. I am trying to get the filters from one embedded visualization and pass it to other visualizations on the web page.
I am initializing my main visualization with this code.
function initViz() {
var containerDiv = document.getElementById("vizContainer"),
url = "https://tableau.Viz",
options = {
hideTabs: true,
loadorder: -1,
hideToolbar: true,
onFirstInteractive: function () {
workbook=SumDash.getWorkbook();
activeSheet = workbook.getActiveSheet().getWorksheets()[0];
SumDash.addEventListener(tableau.TableauEventName.FILTER_CHANGE,onFilterChange);
console.log("Run this code when the viz1 has finished loading.");
}
};
var SumDash = new tableau.Viz(containerDiv, url, options);
When filters are changed on the main visualization, I am getting the field names and applied values and updating the other visualizations with this code.
This code works, but it is very slow. I think part of my problem is that the dashboard I am getting the filters from has multiple worksheets and the below code is looping through each worksheet in the dashboard (21 worksheets on the dashboard and console.log(1) is printing 21 times).
Is there a way to only pass the field names and values from one worksheet and not each worksheet in the dashboard? Is there a more efficient way to do this?
function onFilterChange(){
activeSheet.getFiltersAsync()
.then(function(promise) {
console.log(1);
var fieldName = [];
var fieldValArr = [];
for (var i=0; i< promise.length; i++) {
fieldName.push(promise[i].getFieldName());
var fieldValues = [];
for (var j=0; j< promise[i].getAppliedValues().length; j++) {
fieldValues[j] = promise[i].getAppliedValues()[j].value;
}
fieldValArr.push(fieldValues);
for (var k=0; k<fieldName.length; k++){
activeSheet1.applyFilterAsync(fieldName[k], fieldValArr[k], tableau.FilterUpdateType.REPLACE);
activeSheet2.applyFilterAsync(fieldName[k], fieldValArr[k], tableau.FilterUpdateType.REPLACE);
}
}
})
Thanks!
Tableau Desktop version = 2018.1
https://public.tableau.com/javascripts/api/tableau-2.min.js

Razor - Converting Json result from controller to a complex object

i have a partial view "_SearchPanel" that has year list dropdown, a classes multiselect control, (some other drop downs - ommitted) and a search button.
I want that when i change selection in year list drop down, only my classes list is refreshed/updated, and not the whole partial view on page.
So i use a JsonResult action in my controller (as opposed to the first time load)
public JsonResult BindClasses(int yearId)
{
ClassRepository repClass = new ClassRepository("name=ge");
YearRepository repYear = new YearRepository("name=ge");
var dataClass = repClass.GetClassesByYear(yearId);
var groupedClassOptions = dataClass.GroupBy(x => x.grade).Select(x => new OptionGroupVM()
{
GroupName = "Grade " + x.Key.ToString(),
Options = x.Select(y => new OptionVM()
{
Value = y.classID.ToString(),
Text = y.classname
})
});
return Json(groupedClassOptions);
}
My javascript
var dropDownYear = $('#ddlYear');
dropDownYear.change(function(){
$("#classList").load(url, {yearId: $(this).val()}, function(result){
setOptions($('#classList'), #Html.Raw(Json.Encode(new List<int>(){})), result);
});
});
now the problem is this result is not considered as an object as was the first time (onpageload) here:
jQuery(function ($) {
setOptions($('#classList'), #Html.Raw(Json.Encode(Model.SelectedClasses)), #Html.Raw(Json.Encode(Model.ClassOptions)));
}
How do i correct/cast it to be considered as Model.ClassOptions(type: GroupOptionsVM List) object instead of a Json
What I have tried
var url = '#Url.Action("BindClasses", "Maps")';
var dropDownYear = $('#ddlYear');
dropDownYear.change(function(){
$("#classList").load(url, {yearId: $(this).val()}, function(result){
#{var x = new List<OptionGroupVM>();}
x = result;
setOptions($('#classList'), #Html.Raw(Json.Encode(new List<int>(){})), x);
});
});
this gives me some syntax errors!!
UPDATE
[Referring to the previous question Stephen linked in comments]
Since i had to do it for two dropdown lists with slight difference i had created setOptions function in my script
function setOptions(listBox, selected, groups) {
// Generate options
createGroupedOptions(listBox, selected, groups);
// Attach plug-in
listBox.multiselect({ enableClickableOptGroups: true, onChange: function(){
var selectedClassItems = this.$select.val();
} });
}
function createGroupedOptions(element, selected, groups) {
for (var i = 0; i < groups.length; i++) {
var group = groups[i];
var groupElement = $('<optgroup></optgroup>').attr('label', group.GroupName);
for (var j = 0; j < group.Options.length; j++) {
var option = group.Options[j];
var optionElement = $('<option></option>').val(option.Value).text(option.Text);
if (selected) {
if (selected.toString().indexOf(option.Value) >= 0) {
optionElement.attr('selected', 'selected')
}
} else {
if (option.IsSelected) {
optionElement.attr('selected', 'selected')
}
}
$(groupElement).append(optionElement);
}
$(element).append(groupElement);
}
}
CALLING setOptions function
setOptions($('#classList'), #Html.Raw(Json.Encode(Model.SelectedClasses)), #Html.Raw(Json.Encode(Model.ClassOptions)));
setOptions($('#indicatorList'), #Html.Raw(Json.Encode(Model.SelectedIndicators)), #Html.Raw(Json.Encode(Model.IndicatorOptions)));
Your returning json, so using .load() makes no sense (you would typically use that when the method your calling returns a partial view).
Change your script to create the <optgroup> and <option> elements based on your data your method returns
var url = '#Url.Action("BindClasses", "Maps")';
var dropDownYear = $('#ddlYear');
dropDownYear.change(function() {
$.post(url, { yearId: $(this).val() }, function(data) {
$.each(data, function(index, item) {
var group = item.GroupName;
// use the above to build your <optgroup> element
$.each(item.Options, function(index, item) {
var value = item.Value;
var text = item.Text;
// use the above to build your <option> elements and append to the <optgroup> element
});
// append the <optgroup> to the <select id="classList"> element
});
});
});
Note the details of the code for generating the elements are in the answer to your previous question
You are trying to mix client side code (jQuery) with server side code (.NET) and it won't work. #Html.Raw and JsonEncode are server side methods. You can't use them after the page loads.
In essence, you need to either use jQuery for all of your page interaction and manage the state of the page on the client side or use full MVC (postback) and do everything on the server.
There are technically other options but I just wanted to address the fundamental issue with what you have tried so far.

knockout push values array

when I click on button1 I get object with 50 contacts array (containing collection of arrays with phoneNumbers, Addresses...), then when I click on button 2 I get the same object but my first object is erased whereas I would like to display 50 + 50 = 100 contacts array. I tried concat method but I have some difficulties to implement.
viewModel.initializeListener = function() {
$('#button1').click(function() {
document.getElementById("button2").style.visibility = "hidden";
$('#retrievedContactsDiv').html('');
nbDisplayedContacts = 0;
console.info("test");
viewModel.ui.FlashbackReport.MoreContacts();
});
$('#button2').click(function() {
viewModel.ui.FlashbackReport.MoreContacts();
console.info("test");
});
}; `
viewModel.WeHaveMoreContacts = function(data) {
console.info("test:", data)
if (viewModel.MoreContacts) {
var newArray=ko.mapping.fromJS(data, viewModel.MoreContacts);
var concatenated = newArray.concat(dataArray);
viewModel.MoreContacts.contacts(concatenated);
} else {
viewModel.MoreContacts = ko.mapping.fromJS(data);
var dataArray = viewModel.MoreContacts.contacts();
}
I have a parameter with number of contacts to skip for the server.
function which call the server then call the mapping function :
viewModel.ui.FlashbackReport.MoreContacts()
Problem : Object # has no method 'concat'
I made a fiddle that may help you.
The first part of the function generates new contacts and the second one add them to the existing contacts.
var VM = function () {
var self = this;
self.contacts = ko.observableArray();
self.addMore = function () {
// simulate server response
var offset = self.contacts().length;
var dataFromServer = [];
for (var index = 0; index < 10; index++) {
dataFromServer.push({
name: 'contact ' + offset + index
});
}
// add each new item to existing items.
ko.utils.arrayForEach(dataFromServer, function (item) {
self.contacts.push(item);
});
};
}
Feel free to ask more explanation.
I hope it helps.

Categories