I have the following function below which does a xmlhttprequest based in two targets which i get from the text of certain html elements.
All I need to do is switch the target values around, but without calling them each time in the if statement. Trying to follow the DRY method.
See below -
if(whichSym === "1"){
document.getElementById('priceSym' + whichSym).innerHTML = target;
target2 = document.getElementById('priceSym2').innerHTML;
dataControl.getItem(function(err, data) {
uiControl.changeInput("1", data);
}, target, target2);
}
else if(whichSym === "2"){
document.getElementById('priceSym' + whichSym).innerHTML = target;
target2 = document.getElementById('priceSym1').innerHTML;
dataControl.getItem(function(err, data) {
uiControl.changeInput("1", data);
}, target2, target);
}
Please let me know if you need more context.
To follow the DRY principle you can simply wrap it in a function. Something like this should work:
function (whichSym) {
const otherSym = whichSym === 1 ? 2 : 1; // assuming values can be only 1 and 2
const target = document.getElementById('priceSym' + whichSym).innerHTML;
const target2 = document.getElementById('priceSym' + otherSym).innerHTML;
dataControl.getItem((err, data) => {
uiControl.changeInput("1", data); // not sure what "1" here means, replace with whichSym if needed
}, target, target2);
}
Related
thank you for the help in advance! Please forgive me if this is a stupid question as I a JS noobie.
I am trying to cycle through an array of URL's that I have nested inside of an object. What I am expecting to happen is for the url's (which are google maps) to show up on my website and for the person using my website to be able to click back and forth between the different map URL's. Right now what's happening is the last item (a google maps url) of myCities.index is being properly displayed, but when I click my previous and next buttons it is going to a blank page. I have looked at my JS console and there are no visible errors there. Can anyone give me some advice as to how to fix this? My code is as follows.
const myCities = {
index:
[url1, url2, url3]
}
const prevButton = document.querySelector('.prevBtn');
const nextButton = document.querySelector('.nextBtn');
const map = document.getElementById("myCitiesss");
nextButton.addEventListener('click', nextCity);
prevButton.addEventListener('click', prevCity);
function prevCity() {
myCities.index--;
updateSrc();
checkButtons();
}
function nextCity() {
myCities.index++;
updateSrc();
checkButtons();
}
function updateSrc() {
map.src = myCities.index;
}
function checkButtons() {
prevButton.disabled = false;
nextButton.disabled = false;
if (myCities.index === 2) {
nextButton.disabled = true;
}if (myCities.index === 0) {
prevButton.disabled = true;
}
}
updateSrc();
checkButtons();
The problem is you're treating myCities.index as both the container of your data and as a counter (hence you're running incrementation/decrementation operations on it).
The counter should be a separate variable.
const myCities = [url1, url2, url3]; //<-- can now be a flat array
let index = 0; //<-- this is our counter, i.e. tracker
The relevant code changes are then: (I also took the opportunity to demonstrate some optimisations and efficiencies you can make)
nextButton.addEventListener('click', () => nextPrevCity('next'));
prevButton.addEventListener('click', () => nextPrevCity('prev'));
function nextPrevCity(which) { //<-- one function to handle both next and prev
which == 'next' ? index++ : index--;
map.src = myCities[index];
checkButtons();
}
function checkButtons() {
prevButton.disabled = false;
nextButton.disabled = false;
if (index === myCities.length - 1) //<-- check against array length, not fixed number 2
nextButton.disabled = true;
if (!index) //<-- because 0 is a falsy value, so same as "if (index === 0)"
prevButton.disabled = true;
}
[ -- EDIT -- ]
Forgot the following at the bottom of the code:
map.src = myCities[0];
checkButtons();
What I'm trying to do:
Figure out how to reference/grab geoJSON data from a server.
In this case I'm just using an example on the openLayers doc.
Ideally I'd just be able to print out a features ID/type, but I cannot get it to work.
What's happening:
var selectElement = document.getElementById('type');
var source = vector.getSource();
var feature = source.getFeatures()[0];
var changeInteraction = function() {
if (select !== null) {
map.removeInteraction(select);
}
var value = selectElement.value;
if (value == 'singleclick') {
select = selectSingleClick;
} else if (value == 'click') {
select = selectClick;
} else if (value == 'pointermove') {
select = selectPointerMove;
} else if (value == 'altclick') {
select = selectAltClick;
} else {
select = null;
}
if (select !== null) {
map.addInteraction(select);
select.on('select', function(e) {
document.getElementById('status').innerHTML = feature.getGeometry().getType();
});
console.log(feature);
}
};
I was hoping my innerHTML would display "Polygon" in this case, but no such luck. I've tried various combinations, and been looking over the documentation, can't see what I'm doing wrong.
The server I'm trying to grab the info from is,
https://openlayers.org/en/v4.6.4/examples/data/geojson/countries.geojson
Any help would be appreciated.
(I can attach full code if helpful)
I was able to replicate your program and find the solution for retrieving the Country's name for a selected feature, as mentioned in your comments.
First, remove the following lines. You don't want the first feature of the source file but the first selected feature instead.
var source = vector.getSource();
var feature = source.getFeatures()[0];
Second, define the feature inside the callback function(e) for the select Event. Also, since getFeatures() will return a Collection of features the getArray() method is necessary.
The get(key) method will return a value for a determined key, "name" in this case.
if (select !== null) {
map.addInteraction(select);
select.on('select', function(e) {
var feature = e.target.getFeatures().getArray()[0];
document.getElementById('status').innerHTML = ' ' +
feature.get("name") + ' ' + feature.getId();
});
}
I think I'm on the wrong track here:
I have an event source that gives me updates on the underlying system oprations. The page is intended to show said events in a jquery powered treetable. I receieve the events perfectly but I realized that there were a case I did not handle, the case where an event arrives but is missing it's parent. In this case I need to fetch the missing root plus all potentially missing children of that root node from the database. This works fine too.
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data)
return;
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
});
}
The problem is around the line if (headlessRows[parentEventId]).
When I run it step by step (putting a debugger instruction just before) everything works fine, the headless array is created and filled correctly.
But as soon as I let it run full speed everything breaks.
The logs I printed seems to indicate that the array is not behaving in the way I was expecting it to. If I print the array with a console.log it shows as follow :
(2957754) [empty × 2957754]
length : 2957754
__proto__ : Array(0)
It seems to be missing any actual data. whereas it shows as follow when I execute it step by step:
(2957748) [empty × 2957747, Array(1)]
2957747:[tr.node.UNDETERMINED]
length:2957748
__proto__:Array(0)
I'm missing something but it is still eluding me.
your code is async, you do http request but you treat him as synchronized code.
try this fix
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
async function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
await fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
return new Promise((resolve,reject) =>{
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data){
resolve()
return;
}
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
resolve()
});
})
}
I have a recursive Javascript function which gets the links from one Wikipedia page, follows them, and then gets all of those links (repeating a specified number of times).
It calls itself an unknown number of times to construct an object of a known depth. When it completes, I want to output the object. Currently the object immediately outputs, and is empty, meaning the function obviously isn't waiting for all the recursive calls to complete.
As you can see, I have attempted to use callbacks, but I assume incorrectly. What am I doing wrong, how should I be doing it? I'm going to presume there's a few other things wrong I haven't spotted too; I'm relatively new to Javascript.
$(document).ready(function ()
{
pageLinks[START_PAGE] = {};
//Get initial pages
links = getLinks(START_PAGE, 0, printLinks));
});
function printLinks()
{
console.log(links);
}
function getLinks(currentPage, level, callback)
{
visitedPages.push(currentPage)
var pageLinks = {}
var data = $.getJSON(URL_BEGIN + currentPage + URL_END, function(data)
{
var pages = data.query.pages;
for(var page in pages)
{
pageContentObj = pages[page].revisions[0];
for(var key in pageContentObj) if(pageContentObj[key].length > 100)
{
var pageContent = pageContentObj[key];
//Get links
hyperlinks = getFromBetween.get(pageContent,"[[","]]");
for(var link in hyperlinks)
{
link = hyperlinks[link].split("|")[0]; //Remove friendly name
link = link.replaceAll(" ", "%20");
//Add to pagelist object
prefix = link.split(":")[0];
if(prefix != "Category" && prefix != "File" && prefix != "wikipedia")
if(level < ITERATIONS && !visitedPages.includes(arguments, link))
{
console.log(level + ": " + link)
pageLinks[link] = getLinks(link, level+1, callback); //===Recursive call===
}
}
}
}
});
if(level == 0 && callback) callback();
return pageLinks;
}
Any help is appreciated, thanks in advance.
**EDIT: ** Link: https://github.com/JakeStanger/Wikipedia-Mapper/blob/master/init.js#L53
The recursive call needs to be like this:
var counter = 0;
//the big for loop
counter++;
getLinks(link, level + 1, function(res) {
for (var key in res) { //with an array it would be concat...
pageLinks[key] = res[key];
}
counter--;
if (counter == 0 && callback) callback(pageLinks); //callback if all callbacks called
});
Also remove this weird code:
if(level == 0 && callback) callback();
No you can do:
getLinks(START_PAGE, 0, console.log);
I am trying to make a bookmarklet that when clicked will check the URL of the current tab/window to see if it contains 'char1' and/or 'char2' (a given character). If both chars are present it redirects to another URL, for the other two it will append the current URL respectively.
I believe there must be a more elegant way of stating this than the following (which has so far worked perfectly for me) but I don't have great knowledge of Javascript. My (unwieldy & repetitive) working code (apologies):
if (window.location.href.indexOf('char1') != -1 &&
window.location.href.indexOf('char2') != -1)
{
window.location="https://website.com/";
}
else if (window.location.href.indexOf('char1') != -1)
{
window.location.assign(window.location.href += 'append1');
}
else if (window.location.href.indexOf('char2') != -1)
{
window.location.assign(window.location.href += 'append2');
}
Does exactly what I need it to but, well... not very graceful to say the least.
Is there a simpler way to do this, perhaps with vars or a pseudo-object? Or better code?
A (sort-of) refactoring of dthorpe's suggestion:
var hasC1 = window.location.href.indexOf('char1')!=-1
var hasC2 = window.location.href.indexOf('char2')!=-1
var newLoc = hasC1
? hasC2 ? "https://website.com/" : window.location.href+'append1'
: hasC2 ? window.location.href+'append1' : '';
if (newLoc)
window.location = newLoc;
Calling assign is the same as assigning a value to window.location, you were doing both with the addition assignment += operator in the method anyway:
window.location.assign(window.location.href+='append2')
This would actually assign "append2" to the end of window.location.href before calling the assign method, making it redundant.
You could also reduce DOM lookups by setting window.location to a var.
The only reduction I can see is to pull out the redundant indexof calls into vars and then test the vars. It's not going to make any appreciable difference in performance though.
var hasChar1 = window.location.href.indexOf('char1') != -1;
var hasChar2 = window.location.href.indexOf('char2') != -1;
if (hasChar1)
{
if (hasChar2)
{
window.location="https://website.com/";
}
else
{
window.location.assign(window.location.href+='append1');
}
}
else if (hasChar2)
{
window.location.assign(window.location.href+='append2');
}
Kind of extendable code. Am i crazy?
var loc = window.location.href;
var arr = [{
url: "https://website.com/",
chars: ["char1", "char2"]
}, {
url: loc + "append1",
chars: ["char1"]
}, {
url: loc + "append2",
chars: ["char2"]
}];
function containsChars(str, chars)
{
var contains = true;
for(index in chars) {
if(str.indexOf(chars[index]) == -1) {
contains = false;
break;
}
}
return contains;
}
for(index in arr) {
var item = arr[index];
if(containsChars(loc, item.chars)) {
window.location.href = item.url;
break;
}
}
var location =window.location.href
if (location.indexOf('char1')!=-1 && location.indexOf('char2')!=-1)
{window.location="https://website.com/";}
else if (location.href.indexOf('char1')!=-1) {window.location.assign(location+='append1');}
else if (location.indexOf('char2')!=-1) {window.location.assign(location+='append2');}