I've accessed 5 followers of a GitHub user using AJAX. I'm trying to go three levels deep on each of the first 5 followers returning 5 followers of each. So, initially, return 5 followers then for each of the five followers go three levels deep returning 5 more followers at each level.
How would I go about this? Recursion? Nested for loops?
Also, when I render the first five followers they render all on the same line in my html. Trying to simply append an html break tag on each loop but doesn't seem to work.
Thanks.
$(function() {
$("#submitbtn").on("click", function(e) {
e.preventDefault();
var username = $("#userID").val();
console.log("username " + username);
var userFollower =
"https://api.github.com/users/" + username + "/followers";
$.getJSON(userFollower, function(data) {
console.log(data);
for (i = 0; i < 5; i++) {
var br = "<br>";
var follower = data[i].login;
console.log("Follower " + follower);
$(".follower").append(follower);
$(".container").append(br);
}
});
});
});
Here is an example using some basic recursion. Note that I also modified the DOM manipulation so that each follower was on a new line, in its own div.
I set the depth to 3 so that I could limit the hits to github.
UPDATE [1]
Noticed that you wanted depth = 3 and 5 followers each, and those numbers were not linked. Modified the snippet to unlink those numbers from each other.
var depth = 3;
var number_per_level = 5;
//var tst = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
$(function() {
$("#submitbtn").on("click", function(e) {
e.preventDefault();
var username = $("#userID").val();
getFollowers(0, $(".container"), username);
});
});
function getFollowers(count, $container, username) {
if (count >= depth) {
return false;
}
//console.log("username " + username);
var userFollower =
"https://api.github.com/users/" + username + "/followers";
$.getJSON(userFollower, function(data) {
//console.log(data);
for (let i = 0; i < number_per_level; i++) {
var follower = data[i].login; //tst[i]; //data[i].login;
var $mine = $("<div class='follower'>");
//console.log(`Follower ${follower} follows ${username}`);
$mine.append(follower).appendTo($container);
getFollowers(count + 1, $mine, follower);
}
});
}
.follower {
padding-left: 1em;
border: 1px solid #c0c0c0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="userID" value="tim" /><button id="submitbtn">GO</button>
<div class="container"></div>
If you know how many levels you have to deep dive, then its better to take nested loops rather than recursions.
var git = [{
name: 'a',
fol: [{
name: 'b',
fol: [{
name: 'c'
}]
}]
}, {
name: 'r',
fol: [{
name: 't',
fol: [{
name: 'e'
}]
}]
}];
git.forEach((firstlevel) => {
console.log(firstlevel.name);
firstlevel.fol.forEach((seclevel) => {
console.log(seclevel.name);
seclevel.fol.forEach((thirdlevel) => {
console.log(thirdlevel.name);
});
});
});
Improper handling of recursion leads to infinite calls and may lead to javascript heap out of memory. And also loops are faster than recursions.
Related
I have a data structure like this
{
"stores": [
{ code: 'A7-22', name: 'market'},
{ code: 'A8-22', name: 'drugstore'},
... 250 items
]
}
Then in the code I search a store using:
const code = 'A7-22';
const store = data.stores.find(store => store.code === code)
But I think that could be a good idea to change the data structure to
{
"stores": {
'A7-22': {name: 'market'},
'A8-22': { name: 'drugstore'},
... 250 items
]
}
and now the code it is more easy to handle:
const code = 'A7-22';
const store = data.stores[code]
Now, consider that this code is running in a backend artifact with high traffic and in the future, the store could be > 10.000.
The question is:
There are some performance issues related to this code if I take the option 2 using a large object with "key value strategy"?
Yes, absolutely the second option is faster. Here is the challenge for two cases:
var code = 'A7-22', store={};
var data = {
"stores": [
{ code: 'A8-22', name: 'drugstore'},
]
};
for(var i=1; i<10000; i++) {
data.stores.push({ code: 'x'+i, name: 'v'+i});
}
data.stores.push({ code: 'A7-22', name: 'market'});
var t1 = new Date();
for(var i=1; i<1000; i++) {
store = data.stores.find(store => store.code === code);
}
var t2 = new Date();
var dt = (t2.getTime() - t1.getTime());
document.write("<p> <b>Option 1 (using find):</b> " + code + ": " + store.name + ', dt: '+ dt + " msec</p>");
// -------------------
var data2 = {
"stores": {
'A8-22': {name: 'drugstore'}
}
};
for(var i=1; i<10000; i++) {
data2.stores['x'+i] = {name: 'v'+i};
}
data2.stores['A7-22'] = { name: 'market'};
var t1 = new Date();
for(var i=1; i<1000; i++) {
store = data2.stores[code]
}
var t2 = new Date();
var dt = (t2.getTime() - t1.getTime());
document.write("<p> <b>Option 2 (using array index):</b> " + code + ": " + store.name + ', dt: '+ dt + "msec</p>");
Note that the high traffic you mentioned is not important here as this code is run in clients.
Im having an issue figuring out how to save and load my game with the format Ive used
So I have this
var upgradeButtonsData = [
{icon: 'dagger', name: 'Attack', level: 0, cost: 5, purchaseHandler: function(button, player) {
player.clickDmg += 1;
}},
{icon: 'swordIcon1', name: 'Auto-Attack', level: 0, cost: 25, purchaseHandler: function(button, player) {
player.dps += 5;
}}
];
and I need to save and load it in the same format as the rest of my game for example I am saving my players gold like this
localStorage.setItem("playerGold",this.player.gold);
and then loading it like this
playerGold_save = localStorage.getItem("playerGold") || "0";
this.player.gold = parseInt(playerGold_save);
I would like to do something similiar with the above code but i am not sure how
also if its relevant heres how I use the above code
onUpgradeButtonClick: function(button, pointer) {
// make this a function so that it updates after we buy
function getAdjustedCost() {
return Math.ceil(button.details.cost + (button.details.level * 1.46));
}
if (this.player.gold - getAdjustedCost() >= 0) {
this.player.gold -= getAdjustedCost();
this.playerGoldText.text = 'Gold: ' + this.player.gold;
button.details.level++;
button.text.text = button.details.name + ': ' + button.details.level;
button.costText.text = 'Cost: ' + getAdjustedCost();
button.details.purchaseHandler.call(this, button, this.player);
}
},
also im using Phaser as a framework
EDIT:
Apparently people are confused about what I a asking I do not want info on how to save the gold ive already done that it was just an exaple of how I want to save the upgrades like I need to save the 'Attack's level and cost as well as the 'Auto-Attack's level and cost to load on next game play
sorry for any confusion
EDIT
I WANT THIS CODE TO BE SAVED
var upgradeButtonsData = [
{icon: 'dagger', name: 'Attack', level: 0, cost: 5, purchaseHandler: function(button, player) {
player.clickDmg += 1;
}},
{icon: 'swordIcon1', name: 'Auto-Attack', level: 0, cost: 25, purchaseHandler: function(button, player) {
player.dps += 5;
}}
];
EDIT : Here is the code to save and load the upgrader's data :
function saveUpgrader() {
var save = [];
for(var i = 0; i < upgradeButtonsData.length; i++)
save.push([upgradeButtonsData[i].level, upgradeButtonsData[i].cost]); // [0] = level ; [1] = cost
try { localStorage.setItem('upgrader_save', JSON.stringify(save)); }
catch(e) {
alert('Failed to save upgrader\'s data');
}
}
function loadUpgrader() {
if(!localStorage.getItem('upgrader_save'))
return ;
try {
var json = JSON.parse(localStorage.getItem('upgrader_save'));
for(var i = 0; i < json.length; i++) {
upgradeButtonsData[i].level = json[i][0];
upgradeButtonsData[i].cost = json[i][1];
}
}
catch(e) {
alert('Failed to load upgrader\'s data');
}
}
Call the saveUpgrader function to save the level and cost of each item into the upgrader, or loadUpgrader to load them (it will overwrite current level and cost).
NOTE : If you want to add items to the upgrader, please add it AFTER the existing elements, like this :
var upgradeButtonsData = [
{icon: 'dagger', name: 'Attack', level: 0, cost: 5, purchaseHandler: function(button, player) {
player.clickDmg += 1;
}},
{icon: 'swordIcon1', name: 'Auto-Attack', level: 0, cost: 25, purchaseHandler: function(button, player) {
player.dps += 5;
}},
// Add the new element here
{icon: '...', name: '...', level: 0, cost: 75, purchaseHandler: function(button, player) {
...
}}
];
If you add the new element BEFORE the others the save will be corrupted and do some bad things.
I hope that helped you :)
I have an object that looks like:
var monsters = {
zombies: {
name: "zombie",
hitPoints: 10,
loot: "magic knife"
},
skeleton: {
name: "skeleton",
hitPoints: 15,
loot: "magic shield"
},
ghoul: {
name: "ghoul",
hitPoints: 12,
loot: "magic helm"
}
};
I'm trying to set a function that will randomly select one of the properties in the variable. (zombies, skeleton, ghoul)
Here's what I have:
var travel = function(direction) {
var newRoom = rooms[currentRoom.paths[direction]];
if (!newRoom) {
$("<p>You can't go that way.</p>").properDisplay();
}
else {
currentRoom = newRoom;
$("<p>You are now in the " + currentRoom.name + " Room.</p>").properDisplay();
if (currentRoom.hasMonsters) {
function pickRand(monsters) {
var result;
var count = 0;
for (var prop in monsters)
if (Math.random() < 1/++count)
result = prop;
return $("<p>Holy Crap! There's a" + result + "in here!</p>").properDisplay();
}
}
else {
$("<p>Whew! Nothing here.</p>").properDisplay();
}
}
};
Note: The hasMonsters is in a separate object. It determines if a specific room has a monster or not.
How can I randomly select one of the monsters and insert in the output? I'm guessing I'm calling the object incorrectly and that's why it's not working.
Will something like this work? You can keep your monsters as an object and use Object.keys to fetch your keys (in this case your monsters) as an array. Then it's just a matter of plucking out a random monster with Math.random:
// so you have some object where the keys are your monsters
var monsters = { ghost: '..', skeleton: '..', donald_trump: '..'};
// grab your monsters above as an array
var monsterArray = Object.keys(monsters);
// pick your monster at random
var randomKey = Math.floor(Math.random() * monsterArray.length);
console.log('holy crap we found a ' + monsterArray[randomKey]);
now I see what you're asking. I want the name property called. Right
now it will properly call what I'm guessing is the entire object. How
do i call the name only?
Try using Object.keys()
var monsters = {
zombies: {
name: "zombie",
hitPoints: 10,
loot: "magic knife"
},
skeleton: {
name: "skeleton",
hitPoints: 15,
loot: "magic shield"
},
ghoul: {
name: "ghoul",
hitPoints: 12,
loot: "magic helm"
}
};
document.body.onclick = function() {
var keys = Object.keys(monsters);
var rand = Math.floor(Math.random() * keys.length)
var res = monsters[keys[rand]];
var key = Object.keys(res);
var prop = res[key[Math.floor(Math.random() * key.length)]];
console.log(res, prop);
this.innerHTML += "<br>" + JSON.stringify(prop) + "<br>"
}
click
Im using Jquery datatables to construct a table.
My requirement is like below
This is not a static table, and we are rendering it using json data. Here I'm, rendering the rows dynamically using "aoColumns".
Is there any way to use rowspan so that the cells (1,2,David,Alex) can be spanned.
Does datatables support this kind of table ?
Datatables does not support this kind of grouping out of the box.
But, as in many cases, there is a plugin available.
It is called RowsGroup and is located here: Datatables Forums. A live example is also included.
If you change the JS part in this example to the below you will have your desired output presented to you in the output window.
$(document).ready( function () {
var data = [
['1', 'David', 'Maths', '80'],
['1', 'David', 'Physics', '90'],
['1', 'David', 'Computers', '70'],
['2', 'Alex', 'Maths', '80'],
['2', 'Alex', 'Physics', '70'],
['2', 'Alex', 'Computers', '90'],
];
var table = $('#example').DataTable({
columns: [
{
name: 'first',
title: 'ID',
},
{
name: 'second',
title: 'Name',
},
{
title: 'Subject',
},
{
title: 'Marks',
},
],
data: data,
rowsGroup: [
'first:name',
'second:name'
],
pageLength: '20',
});
} );
Here is a screenshot of the result:
I tried the RowsGroup plugin, but it achieves this just by hijacking the DataTables sort mechanism. If you tell it to group a given column, what it does for you is basically to apply a sort to that column that you can't turn off. So, if you want to sort by another column, you can't. That didn't work in my application.
Instead, here's a working fiddle for a recipe that allows you to achieve this result:
https://jsfiddle.net/bwDialogs/fscaos2n
The basic idea is to flatten all of your multi-row data into a single row. Content in your 2nd, 3rd, etc. rows are stored as a hidden <script> template tag within your first row.
It works by using DataTables' drawCallback function to manipulate the DOM once DataTables has rendered it, without confusing DataTables by having to try parsing rowspan cell content.
Since this modifies the DOM after DataTables has done its magic, your multi-row sections will stick together even with pagination, searching, and sorting.
Cheers.
add a below code and modify according to your requirement
$(window).on("load",function() {
MakeRows();
addRowspan();
$(".paginate_button").on("click", function() {
MakeRows();
addRowspan();
});
});
function MakeRows() {
var tmp_tbl = $("#dashboardDetails");
var _l = tmp_tbl.find("tr");
var _td = "",_t_td = "", old_txt = "",_t_txt = ""; _tr_count = 1;_tr_countadd = 1;
for(i = 0;i< _l.length; i ++) {
_t_td = tmp_tbl.find("tr").eq(i).find("td").eq(0).find("span");
_t_txt = $(_t_td).text();
_t_txt = _t_txt.replace(/\//,"_");_t_txt = _t_txt.replace(/\//,"_");
if (_t_txt.length > 0) {
if(_t_txt != old_txt) {
if($(_l).eq(i).hasClass(_t_txt) == false) {
_tr_count = 1;_tr_countadd = 1;
$(_l).eq(i).addClass("" + _t_txt + "").addClass(_t_txt + "_" + i);
}
old_txt = _t_txt;
} else {
_tr_count = _tr_count + 1;
if (_tr_countadd == 1) {
$(_l).eq(i).addClass("" + _t_txt + "").addClass(_t_txt + "_" + i)
.addClass("hiddenClass").addClass("maintr").attr("trcount", _tr_count).attr("addedtrcount", "maintr");
_tr_countadd = _tr_countadd + 1;
} else {
$(_l).eq(i).addClass("" + _t_txt + "").addClass(_t_txt + "_" + i)
.addClass("hiddenClass").attr("trcount", _tr_count)
}
}
}
_t_td = "";
}
}
function addRowspan() {
var t_txt = "";
var _alltrmain = $(".maintr");
var _h_td = ["0","10","11","12","13"];
for (i = 0; i <= _alltrmain.length; i ++) {
for (j = 0; j <= _h_td.length; j ++) {
t_txt = $(_alltrmain).eq(i).attr("trcount");
$(_alltrmain).eq(i).prev().find("td").eq(_h_td[j]).attr("rowspan", t_txt);
}
}
}
I its basic but I am new to javascript. I am trying to loop through the array and match the objects that == my key.
this is what i am using right now, it works but i am only matching the first object that matches, sometimes there will be multiple objects that match.
Here is what i have now
var chartSeries = chartService.getSeries();
var marker.options.subdivision.id = 1345
var matchingSeries = Enumerable.From(chartSeries).Where('x => x.id == "' + marker.options.subdivision.id + '"').ToArray();
var series = {
id: matchingSeries[0].id,
name: matchingSeries[0].name,
data: matchingSeries[0].data,
lineWidth: 5
};
I need to include a for loop to match all objects.
var subIdSeries = [];
var subId = marker.options.subdivision.id;
var series = {
id: matchingSeries[0].id,
name: matchingSeries[0].name,
data: matchingSeries[0].data,
lineWidth: 5
};
for (var i = 0; i < chartSeries.length; i++) {
if (subId == chartSeries.id) {
push.subIdSeries(subId)
}
}
Change
if (subId == chartSeries.id) {
push.subIdSeries(subId)
}
to
if (subId == chartSeries[i].id) {
subIdSeries.push(subId)
}
Without seeing the whole script, from what you have so far, I can suggest:
if (subId == chartSeries[i].id) {
subIdSeries.push(subId)
}