How to prevent duplicate rows from being displayed in html? - javascript

I've followed and completed this tutorial https://github.com/dappuniversity/election/tree/2019_update. However, duplicate rows show up at the end when I'm adding new votes in (shown in picture).
I'm not familiar with dApps, web development, or javascript so I don't know where my error is.
Code from https://github.com/dappuniversity/election/tree/2019_update.
I don't know where adding the new rows came in and I'm trying to prevent it.

the problem is in the asynchronous nature of JavaScript the app is not waiting for the response of the blockchain before removing the old so what happens is that the data get inserted to the dom two times, the fix is to handle the promises differently. Group all the promise calls to get candidates to an array, then waiting until all of them are resolved to add them to the dom.
App.contracts.Election.deployed()
.then(function(instance) {
electionInstance = instance;
return electionInstance.candidatesCount();
})
.then(function(candidatesCount) {
const promises = [];
// Store all prosed to get candidate info
for (var i = 1; i <= candidatesCount; i++) {
promises.push(electionInstance.candidates(i));
}
// Once all candidates are received, add to dom
Promise.all(promises).then(candidates => {
var candidatesResults = $("#candidatesResults");
candidatesResults.empty();
var candidatesSelect = $("#candidatesSelect");
candidatesSelect.empty();
candidates.forEach(candidate => {
var id = candidate[0];
var name = candidate[1];
var voteCount = candidate[2];
// Render candidate Result
var candidateTemplate =
"<tr><th>" +
id +
"</th><td>" +
name +
"</td><td>" +
voteCount +
"</td></tr>";
candidatesResults.append(candidateTemplate);
// Render candidate ballot option
var candidateOption =
"<option value='" + id + "' >" + name + "</ option>";
candidatesSelect.append(candidateOption);
});
});
return electionInstance.voters(App.account);
})

Related

How to get groups a given user is a part of in SharePoint?

I'm trying to get the groups a given user (typed into a textbox in page) is a member of. Haven't had much success so decided to get all the groups, iterate through their users to find the groups the user is a part of. Tried the following but can't find a way to iterate through the users.
what am I missing? is there a better way to achieve my main goal?
var oGroupCollection, clientContext, loadedGroup, oUserCollection, oUser ;
function GetAllSiteGroups() {
// You can optionally specify the Site URL here to get the context
// If you don't specify the URL, the method will get the context of the current site
var clientContext = new SP.ClientContext("http://MyServer/sites/SiteCollection");
// Get Site Group Collection object
oGroupCollection = clientContext.get_web().get_siteGroups();
//oUserCollection = oGroupCollection.getByTitle('sp_red_dehn_zigaretten').get_users();
//console.log(oUserCollection);
// Load Site groups
clientContext.load(oGroupCollection);
// Execute the query to the server.
clientContext.executeQueryAsync(onsuccess, onfailed);
}
function onsuccess() {
// Iterate through each item
var oEnumerator = oGroupCollection.getEnumerator();
while (oEnumerator.moveNext()) {
var oGroup = oEnumerator.get_current();
console.log(oGroup);
console.log("Title of the group is: " + oGroup.get_title() + "\n");
oUserCollection = oGroup.get_users();
console.log(oUserCollection);
clientContext.load(oUserCollection);
clientContext.executeQueryAsync(onsuccess2, onfailed);
}
}
function onfailed(sender, args) {
console.log('Failed' + args.get_message() + '\n' + args.get_stackTrace());
}
function onsuccess2() {
// Iterate through each item
var oEnumerator = oUserCollection.getEnumerator();
while (oEnumerator.moveNext()) {
oUser = oEnumerator.get_current();
console.log(oUser);
//console.log("Title of the group is: " + oUser.get_title() + "\n");
}
}

Stuck with JSON API Call in Javascript

I am trying to build a Calculator where you can Pick different Cryptocurrencies and build a Portfolio for Testing and Tracking. I choose Coingecko API v3 for this and use Fetch to do the API Calls. https://www.coingecko.com/en/api
The API Calls are working and I get JSON Data from the Server. I built a Function that is delivering the Top 100 Coins, putting them into a Datalist-Tag for Choosing from an Input:
function fetch_coinlist(url) {
fetch(url)
.then(function(response) {
if (response.status !== 200) {
alert("Can Not get Price Api! Status: " + response.status);
return;
}
response.json().then(function(data) {
document.getElementById("coinlist").innerHTML = "";
for (i = 0; i <= 99; i++) {
const toplist = document.createElement("option");
toplist.id = data[i].symbol;
toplist.innerHTML =
data[i].symbol.toUpperCase() + " - " + data[i].name;
document.getElementById("coinlisting").appendChild(toplist);
//console.log(data[i].id);
//console.log(data[i].name);
//console.log(data[i].symbol);
//console.log(data[i].image);
//console.log(data[i].current_price);
}
});
})
.catch(function(err) {
alert("Can Not get Price Api! Status: " + err);
});
}
<input list="coinlisting" id="coinlist" name="coinlist" class="curser-choose" />
<datalist id="coinlisting" placeholder="Choose Coin"></datalist>
This is working, I am using a For loop to go through the response. I try to Display the Price for a Coin if the User picked one Option from this Datalist and for further functionality I think it would be best that I could call an object like data.coinname.current_price so I can build a Function where i could pass a string to it and get the price for that coin.
However, right now I would have to use data[0].current_price for the current Price of the first item in the list. The items on the called List can Change over time, so I can not make a static assignment, I think I could do this each time I call the API but it would not benefit my target to have a function that I can feed with a name as a string to do the Price Call.
It is possible to get the Price in the same call as the list but I can not figure out how I would be able to do what I have in mind with that. On the site for the API are different calls listed, one of the first is the /coins/list call and it says "Use this to obtain all the coins’ id in order to make API calls" and gives a JSON object for each available coin like:
{
"id": "1inch",
"symbol": "1inch",
"name": "1inch"
}
Do I need to do this call first in order to achieve what I have in mind? But I'm unsure how that would help me get the solution I am looking for... I am struggling to find a solution for this and feel stuck, I feel like I don't understand it properly and it should be not as hard as I think it is right now :D If you have an idea of how to accomplish this please let me know!
You could do something like this. I kept the html simple.
fetch_coinlist: fetches a coin list. After fetching the coins list it converts the result to an object instead of a list. Each coin can be accessed using coins["<coin id>"].
show_coinlist does the visualisation
addEventListener catches when you select an item.
const gecko = "https://api.coingecko.com/api/v3/";
var coins = {};
// selector actions
const selector = document.querySelector('#coinlisting');
const info = document.querySelector('#info');
selector.addEventListener('change', event => {
info.innerHTML = "Selected item: " + selector.value + " : " + coins[selector.value].name;
});
function fetch_coinlist() {
fetch(gecko + "coins/list")
.then(function(response) {
if (response.status !== 200) {
alert("Can Not get List Api! Status: " + response.status);
return;
}
response.json().then(function(data) {
coins = {};
for (let i = 0, l = data.length; i < l; i++) {
let {id, ...info} = data[i];
coins[id] = info;
}
show_coinlist();
});
})
.catch(function(err) {
alert("Can Not get Price Api! Status: " + err);
});
}
function show_coinlist(){
for (let id in coins) {
let item = coins[id];
const toplist = document.createElement("option");
toplist.value = id;
toplist.innerHTML = item.symbol.toUpperCase() + " - " + item.name;
document.getElementById("coinlisting").appendChild(toplist);
}
}
fetch_coinlist();
<select id="coinlisting" placeholder="Choose Coin"></select>
<div id="info"></div>

Selecting item2 on page 1 returns item1 on page2

I am dynamically creating rows and tables from a database to display a list of read-only items. When one of these items is clicked, the page should reload to a different window and display the relevant results related to the clicked item.
I have 99% of this working, however when I click the first row (let's say "item1" the next window reflects undefined. When I click the second row ("item2") the window reflects the results of item1. When I click the third row ("item3") the window reflects the results of item2.
The most I understand is that I may not be storing the variables correctly.
My closest guess is this may be a solution for queryString, however I am not sure how or where to implement it.
I have provided all relevant code commented for the sake of anyone else who may have this problem.
var customApp = function(){
// Establish Variables
var salonName
var salonDomainLink
var salonAddress
var salonPhoneNumber
var salonSelection
// Queries Salons class
var query1 = new Parse.Query("Salons");
query1.find({
success: function(results) {
// Changes search results from JSON Object to ?something readable?
var searchResults = JSON.parse(JSON.stringify(results))
// Loops through every result and creates variables with each specific result
for ( var i in searchResults) {
salonName = searchResults[i].name;
salonDomainLink = searchResults[i].domainLink;
// Creates a new row for each item in table
var newrow = $('<tr>').text('').appendTo('#searchTable');
// Adds a cell for each salonName in row
var nameCell = $('<td>').text(salonName).appendTo(newrow);
// Adds an id of the salon name + 'Id' to each row
var cellId = nameCell.attr("id", salonName.replace(/\s+/g, '') + "Id")
// Changes class of each cell
nameCell.addClass("text-left font-w600 text-primary");
}
// Passes clicked salon name to a variable for use on another page
$('#searchTable tr td').click(function(){
// Acquires text value of the specific td of tr
salonSelection = $(this)[0].childNodes[0].nodeValue
// Saves the variable to local storage (can be retrieved with "localStorage.salonSelection")
delete localStorage.salonSelection;
window.localStorage.salonSelection = salonSelection;
window.location = 'base_pages_schedule_1.html';
});
},
error: function(error) {
alert("Error: " + error.code + " " + error.message + ". Please contact Support.");
}
});
query1.equalTo("name", localStorage.salonSelection);
query1.find({
success: function(results) {
var searchResults = JSON.parse(JSON.stringify(results))
// Loops through every result and creates variables with each specific result
for ( var i in searchResults) {
window.localStorage.salonName = searchResults[i].name;
window.localStorage.salonDomainLink = searchResults[i].domainLink;
window.localStorage.salonAddress = searchResults[i].address;
window.localStorage.salonPhoneNumber = searchResults[i].phoneNumber;
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message + ". Please contact Support.");
}
});
$('#salon-name').text(localStorage.salonName);
$('#salon-address').text(localStorage.salonAddress);
$('#salon-phone-number').text(localStorage.salonPhoneNumber):};
query.find() is asynchronous so it won't set new values until after you set the text() in the dom
Move the dom updates into your find() success callback
query1.find({
success: function(results) {
var searchResults = JSON.parse(JSON.stringify(results))
// process results
// then update dom
$('#salon-name').text(localStorage.salonName);
},
error: function(error) {
alert("Error: " + error.code + " " + error.message + ". Please contact Support.");
}
});
Also note that your for loop is rewriting a new value to the storage keys on each iteration of the loop so only the last one gets stored. Not sure what your storage objectives are here

JS, multiple JSON requests and callback functions

I need some help. I'm quite new to Javascript, I'm currently trying to do something using two differents api: SongKick and Deezer. The idea is simple, on the page you can type your city, 1) I do a first request to the Songkick Api to get the ID of this city, 2) then with the ID, I do another request to get a list of concerts and I only take the name of the artist (20 maximum), 3) then I with the list of names I use the deezer Api to get the picture of the artist and a mp3 preview.
I've tried many ways but I can't access the data everywhere of course, and I don't know how to use callback cause there is too many things, if you can take a look that would be awesome.
Thanks!
artistsArray = [];
artistsArray2 = [];
arr = [artistsArray,[],[]];
var dispName;
var areaId;
function search(){
area = document.getElementById('band').value;
function songKickArea(callback){
$.getJSON('http://api.songkick.com/api/3.0/search/locations.json?query=' + area + '&apikey=tIhpFoFn0dWpQ72A',function(data){
var areaId = data['resultsPage']['results']['location'][0].metroArea.id;
callback(areaId);
});
console.log("1 is done");
}
function findAreaId(callback){
songKickArea(function(callback){
console.log(callback);
});
$.getJSON("http://api.songkick.com/api/3.0/metro_areas/" + areaId + "/calendar.json?apikey=tIhpFoFn0dWpQ72A",function(data){
for (var i=0; i<20 ; i++)
{
artistsArray.push(data['resultsPage']['results']['event'][i].performance[0].displayName);
}
callback(artistsArray);
});
console.log("2 is done");
}
function addInfos(callback){
for (var i=0; i<20 ; i++)
{
DZ.api('/search?q=artist:' + '"'+ artistsArray[i]+'"' +'?limit=1', function(json){
if(json.data[0]){
artistsArray2.push({preview:json.data[0].preview, picture: json.data[0].artist.picture})
}
});
}
console.log("3 is done");
callback();
}
function runSearchInOrder(callback) {
songKickArea(function() {
findAreaId(function() {
addInfos(function() {
console.log(areaId);
});
});
});
}
runSearchInOrder(function(){console.log('finished')});
}
EDIT 09/17/2015
Thanks Vittore, I took a look at promises in JS and it's very interesting and perfect in my case. So now I'm here :
function songKickArea(areaId){
area = document.getElementById('band').value;
return $.getJSON('http://api.songkick.com/api/3.0/search/locations.json?query=' + area + '&apikey=XXXXXXX',function(data){
});
}
function findAreaId(data){
var areaId = data['resultsPage']['results']['location'][0].metroArea.id;
return $.getJSON("http://api.songkick.com/api/3.0/metro_areas/" + areaId + "/calendar.json?apikey=XXXXXXX",function(data){
});
}
function addInfos(data){
for (var i=0; i<20 ; i++)
{
artistsArray.push(data['resultsPage']['results']['event'][i].performance[0].displayName);
DZ.api('/search?q=artist:' + '"'+ artistsArray[i]+'"' +'?limit=1', function(json){
if(json.data[0]){
artistsArray2.push({preview:json.data[0].preview, picture: json.data[0].artist.picture})
}
});
}
}
And I use this onClick:
songKickArea().then(findAreaId).then(addInfos).then(createList);
So everything is working fine, in addInfos my array artistsArray2 get all the infos I need from deezer (preview and picture). But now the next step is to create a list to display these artists (or tracks) so the next function is like this.
function createList(json){
var html = '<ul>';
for (var i=0; i<17; i++)
{
html+= '<li>';
html += '<div class="picture">' + '<div class="player"><img src="svg/play43.svg" ></div>'+ '<a href=' + artistsArray2[i].preview + '>' + '<img src=' + artistsArray2[i].picture + '>' + '</a>' +'</div>';
html+= '<div class="arrow"><img src="css/svg/arrow487.svg"></div>';
html+= '</li>';
}
html+= '</ul>';
$('#results').append(html);
}
But here I have no idea how to pass the value of a full array from the last function to this one, could you help me ? Thanks a lot !
UPDATE: Little clarification on multiple calls to the services and array of results.
You original code has addInfos method that iterates ( for loop ) through array and calling web service in that loop. What you want to do is to get results of each of those calls all together. While there are many ways of doing that, what I am showing you is using array.map to "map" each element of an array with data from step X to the promise returned by AJAX call. Let me give an example:
Say you have an array:
var artistIds = [6664009,6664010,6664011]
Now you can map it to promises:
var artistCalls = artistIds.map(function(id) {
return $.getJson('~ get artists data service url ~' + id)
}
Which will give you array artistCalls each element of which will eventually have resolved promise with the data you need. While you can do all the crazy stuff with it, the easiest way of getting data from ALL calls is to use $.when helper method:
$.when(artistCalls).then(function(artists) {
// here artists will array where each element is data returned by each AJAX call
})
Now if you want to render html to show all artists on the page you might have code like that:
function renderArtistHtml(artist) {
return '<li>'
+= '<div class="picture"><div class="player"><img src="svg/play43.svg" ></div><img src="' + artistsArray2[i].picture + '"></div>'
+= '<div class="arrow"><img src="css/svg/arrow487.svg"></div>'
+= '</div></li>';
}
And a function that renders entire list:
function renderAllArtistsHtml(artists) {
return '<ul>' + artists.map(renderArtistHtml) + '</ul>'
}
Now that you have it you can create whole chain of your functions together:
$(... my button selector ...).on('click',function(e) {
var area = ... get area
songKickArea(area)
.then(findAreaId) // this thing returns promise that returns array
.then(addInfos) // this thing returns $.when(arr.map(...))
.then(renderAllArtistsHtml) // this thing converts array of data from all calls from previous step to html layout
.then(function(html) { // this part just adds it to DOM
$('#results').append(html);
});
})
Just answered similar question here.
Basically every ajax method in jquery returns promise ( and if your api does not return promise (like DZ.api ) you can wrap it in a $.deferred )
Once you return promises from your functions you can chain them:
function myajax1() {
return $.getJson(...)
}
function myajax2(data) {
return $.getJson(...)
}
myajax1().then(myajax2)
This will call myajax2 with data returned by myajax1 ajax call
You can chain it as many times as you want.
In case you need to wait for several you can use $.when:
$.when([myajax11(), myajax12()]).then(myajax2)
So closer to your actual code, you have 3 api calls:
songkick locations
songkick metro_areas
DZ.api
last one will require wrapping up in a promise, see example here: https://learn.jquery.com/code-organization/deferreds/examples/
Declare 3 functions:
function getLocations(area) {
return $.getJson(....) // location query
}
function getMetroArea(data) {
var areaId = data['resultsPage']['results']['location'][0].metroArea.id
return $.getJson(...) // metro query
}
function getArtists(data) {
var artist = data['resultsPage']['results']['event'][i].performance[0].displayName
return DZAPIWraper(...)
}
And chain them:
getLocations(...).then(getMetroArea).then(getArtists)
In case you really need to do several calls for several artists in the last step, your code will look similar to:
function getArtists(data) {
var artists = getArtistsArrayFromMetro(data)
var artistsCallbacks = artists.map(function(a) {
return DZAPIWrapper(...)
})
return $.when(artistCallbacks)
}
and that full chain is:
getLocations(...).then(getMetroArea).then(getArtists).then(function(artists) {
// here artists going to be all artists data from all api calls to DZ.api
})

Using D3 to read data into associative arrays

I'm trying to loop through a set of values and read in separate files (using d3.js) into javascript associate arrays , but the argument is not being passed properly into the internal function. For example:
var reg_list = [];
var all_region_data = [];
reg_list[0]="region1";
reg_list[1]="region2";
// Function to read in data from all regions in reg_list.
function read_regional_data(region_list) {
for (i=0;i<reg_list.length;i++) {
region = region_list[i];
console.log("Read data for " + region) // THIS RETURNS REGION1, THEN
// REGION2
all_region_data[region]=new Array()
d3.csv('filepath' + region + '.csv', function(csv){
console.log('reading for ' + region) // THIS RETURNS REGION2 TWICE
csv.map(function(x) {
all_region_data[region].push(x.cause);
})
console.log("Finished Reading Data for " + region)
})
}
}
When I execute this, I iterate through both regions in the loop, but region1 is never passed into the d3.csv function. This may have something to do with the d3.csv being run asynchronously? Any thoughts on how to avoid or improve this are appreciated.
Use recursion instead of the loop to iterate over the regions --
var reg_list = [],
all_region_data = [];
reg_list[0]="region1";
reg_list[1]="region2";
function read_regional_data(i) {
var region = reg_list[i];
console.log("Read data for " + region);
all_region_data[region]=new Array();
d3.csv('filepath' + region + '.csv', function(csv){
console.log('reading for ' + region);
csv.map(function(x) {
all_region_data[region].push(x.cause);
});
console.log("Finished Reading Data for " + region);
if(i < reg_list.length) {
read_regional_data(i+1);
}
});
}
read_regional_data(0);

Categories

Resources