0

I am trying to dynamically create href links within Mapbox popups. When hovering over a location, I am returned an array, for example:

"Feature","properties":{"field_1":71,"city":"Gothenburg",
"course1":"EMM-Nano","course2":"EMHRPP","course3"
:"MFAMILY","course4":"NA","course5":"NA","course6":"NA",
"course7":"NA","course8":"NA","course9":"NA","course10":"NA",
"course11":"NA","course12":"NA","course13":"NA","course14":"NA",
"course15":"NA","course16":"NA","lon":11.97456,"lat":57.70887,
"website1":"http://www.emm-nano.org/",
"website2":"http://ws1.roehampton.ac.uk/admissions/erasmusmundus/hrp/index.html",
"website3":"http://www.mfamily.eu/",
"website4":"NA","website5":"NA","website6":"NA",
"website7":"NA","website8":"NA","website9":"NA",
"website10":"NA","website11":"NA","website12":"NA",
"website13":"NA","website14":"NA","website15":"NA",
"website16":"NA","code":"Gothenburg","title":"Gothenburg"

As you can see, the urls which will serve as href are strings within the array. Each course is connected to a website so that course1 should be linked to website1, course2 should be linked to website2 and so on. At this point, my popups only display courses and links separately for example:

enter image description here

with the following code to remove the NA and other unwanted values:

  var feature = features[0];
  function htmlFromProps(props) {
    var html = "";
    var i = 0;
    for (p in props) {
      if (props[p] && props[p] != "null" && props[p] != "NA") {
        html += "<div>" + (i === 0 ? "<strong>" : "");
        html += props[p];
        html += (i++ === 0 ? "</strong>" : "") + "</div>\n";
      }
    }
    return html;
  }

//delete unnecessary elements*
  delete feature.properties["field_1"];
    delete feature.properties["lon"];
      delete feature.properties["lat"];
        delete feature.properties["code"];
        delete feature.properties["title"];
  // Populate the popup and set its coordinates
  // based on the feature found.
  popup.setLngLat(feature.geometry.coordinates)
      .setHTML(htmlFromProps(feature.properties))
      .addTo(map);

}

This works, but the links are not attached to the course names. I am interested in only displaying the course names themselves that include hrefs Is there a programmatic way to go about this in JS without using CSS? I have researched several examples as this one but it is not applicable to the structure as it is now. Any advice on how to go about this problem would be appreciated.

2 Answers 2

1

Parse the properties into course and website arrays and then process them to match them up.

The following is an example:

var properties = {
  "city": "Gothenburg",
  "course1": "EMM-Nano",
  "course2": "EMHRPP",
  "course3": "MFAMILY",
  "course4": "NA",
  "course5": "NA",
  "course6": "Course6",
  "course7": "Course7",
  "course8": "Course8",
  "course9": "Course9",
  "course10": "Course10",
  "course11": "Course11",
  "course12": "Course12",
  "course13": "Course13",
  "course14": "Course14",
  "course15": "Course15",
  "course16": "Course16",
  "course17": "Course17",
  "course18": "Course18",
  "course19": "Course19",
  "course20": "Course20",
  "course21": "Course21",
  "website1": "url1",
  "website2": "url2",
  "website3": "url3",
  "website4": "NA",
  "website5": "NA",
  "website6": "url6",
  "website7": "url7",
  "website8": "url8",
  "website9": "url9",
  "website10": "url10",
  "website11": "url11",
  "website12": "url12",
  "website13": "url13",
  "website14": "url14",
  "website15": "url15",
  "website16": "url16",
  "website17": "url17",
  "website18": "url18",
  "website19": "url19",
  "website20": "url20",
  "website21": "url21",
};


alert("Output:" + htmlFromProps(properties));

function htmlFromProps(props) {
  var city = "";
  var courses = [];
  var websites = [];
  for (p in props) {
    if (props[p] && props[p] != "null" && props[p] != "NA") {
      if (isCourse(p)) {
        courses[getIndex(p)] = props[p];
      } else if (isWebsite(p)) {
        websites[getIndex(p)] = props[p];
      } else {
        city = props[p];
      }
    }
  }
  return buildHTML(city, courses, websites);
}

function isCourse(propname) {
  return (propname.indexOf("course") != -1);
}

function isWebsite(propname) {
  return (propname.indexOf("website") != -1);
}

function getIndex(propname) {
  var indexRegEx = new RegExp("^.*?(\\d+)$");
  var matches = indexRegEx.exec(propname);
  if ((matches != null) && (matches.length == 2)) {
    return parseInt(matches[1]);
  } else {
    return 0;
  }
}

function buildHTML(city, courses, websites) {
  var html = "";
  html += "<div><strong>";
  html += city;
  html += "</strong></div>\n";

  for (i = 1; i < courses.length; i++) {
    if (courses[i]) {
      html += "<div>";
      html += "<a href='" + websites[i] + "'>" + courses[i] + "</a>";
      html += "</div>\n";
    }
  }
  return html;
}

Just ignore the var properties and the alert statements at the top of this snippet and replace the htmlFromProps() function with your original and add all the remaining functions in this snippet below htmlFromProps() to your code.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you, that makes sense. Is there a way to put the :url into an href? Would one have to then spilt the new array by : ?
The href is aded to the buildHTML. This can be changed in any way needed to generate the required HTML. The answer has been edited to add the href tag.
For some reason, the code is not working properly if I have more than 10 different courses and websites. For example, if I have 15 of courses, it will only show course11, course12, course13, course14, and course15, but not the first 10. And if I have 20 courses, it will show course11 - course19and skip course20 as well as the first ten. Is there a way to fix this?
The regex was not correctly parsing the 2 or more digit numbers. The .* was matching all digits except the last one - so only returning the last digit as a match each time. The new ? qualifier will only match non digits at the end - leaving all the training digits to match. Also the buildHTML needed to check for array elements that had not been populated - so the if (cources[i]) was added - otherwise empty courses were output.
That makes sense. Could you update the code so that it will take into account 2-digit numbers as well? Thanks in advance
|
0

var html = getHtml()
console.log(html)
document.write(html)
function getHtml(){
  var links = getLinks(getData())
  return links.map((x)=>{
    return `<a href="${x.website}">${x.course}</a>`
  }).join(",\n")  
}

function getLinks(data){
  return Object.keys(data).reduce((last,x)=>{
    if (/course(\d+)/.test(x)){
      var websiteKey = 'website'+RegExp.$1
      if(data[x] != 'NA' && data[websiteKey] && data[websiteKey]!='NA'){
        last.push({
          course:data[x],
          website:data[websiteKey].replace('http: //','http://')
        })
      }
    }
    return last
  },[])
}

function getData(){
  return {
    "field_1": 71,
    "city": "Gothenburg",
    "course1": "EMM-Nano",
    "course2": "EMHRPP",
    "course3": "MFAMILY",
    "course4": "NA",
    "course5": "NA",
    "course6": "NA",
    "course7": "NA",
    "course8": "NA",
    "course9": "NA",
    "course10": "NA",
    "course11": "NA",
    "course12": "NA",
    "course13": "NA",
    "course14": "NA",
    "course15": "NA",
    "course16": "NA",
    "lon": 11.97456,
    "lat": 57.70887,
    "website1": "http: //www.emm-nano.org/",
    "website2": "http: //ws1.roehampton.ac.uk/admissions/erasmusmundus/hrp/index.html",
    "website3": "http: //www.mfamily.eu/",
    "website4": "NA",
    "website5": "NA",
    "website6": "NA",
    "website7": "NA",
    "website8": "NA",
    "website9": "NA",
    "website10": "NA",
    "website11": "NA",
    "website12": "NA",
    "website13": "NA",
    "website14": "NA",
    "website15": "NA",
    "website16": "NA",
    "code": "Gothenburg",
    "title": "Gothenburg"
}}

5 Comments

Thank you for this. How to get rid of the space in between http: and // ?
updated, just replace, you can find a way for your own
Thanks, any idea why I get Uncaught ReferenceError: getData is not defined ?
Maybe I have to reference an external script file?
getData() means get the Data, case you have your data, replace it, case not you can copy all code in snippet, getData is defined in the last section

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.