Accessing deeper objects with Mustache.JS - javascript

This is part of my JSON file
{
"topic": {
"topicTitle": "Living things and the environment",
"subTopics": [
{
"subTopicTitle": "Identifying, namimg and classifying",
"subTopicShortName": "identifyingNamingClassifying",
"subTopicDescription": "About one and a half million kinds of organisms have been discovered. How do we identify, name and classify them?",
"subTopicQuestions": [
{
"question": "Use the key to identify the plants a to e in picture 1.",
"subTopicQuestionAssetLinks": [
"href://file/filename/image1.jpeg"
],
"subTopicQuestionAssetCaptions": [
"Caption 1"
]
},
And this is my javascript
<script>
$.getJSON('data.json', function(data1) {
intro_template = "<h1> {{topic.topicTitle}} </h1> <h2> {{topic.subTopics}} </h2>";
html = Mustache.to_html(intro_template, data1);
    $('.intro_template_container').html(html);
});
</script>
The h1 works perfectly displaying "Living things and the environment"
Beween the H2 tags I would like to show the "subTopicTitle" of "identifying, name and classifying"
How is this possible?

Since subTopics is an array, you will have to use a mustache section:
<h1>{{topic.topicTitle}}</h1>
{{#topic.subTopics}}
<h2>{{subTopicTitle}}</h2>
{{/topic.subTopics}}

Related

How to implement hyperlinks in JSON & D3 plugin?

My goal here is to have the childless nodes contain hyperlinks. This is the D3 plugin I'm basing things off of: https://github.com/deltoss/d3-mitch-tree
Image Example
I'm newer to JS and JSON so I'm having difficulties on figuring out how to proceed, especially since there's little to refer to in regard to hyperlinks & JSON. If there's a better way to go about this, I'm certainly open to new ideas.
Thank you in advance
<script src="https://cdn.jsdelivr.net/gh/deltoss/d3-mitch-tree#1.0.2/dist/js/d3-mitch-tree.min.js"></script>
<script>
var data = {
"id": 1,
"name": "Animals",
"type": "Root",
"description": "A living that feeds on organic matter",
"children": [
{
"id": 6,
"name": "Herbivores",
"type": "Type",
"description": "Diet consists solely of plant matter",
"children": [
{
"id": 7,
"name": "Angus Cattle",
"type": "Organism",
"description": "Scottish breed of black cattle",
"children": []
},
{
"id": 8,
"name": "Barb Horse",
"type": "Organism",
"description": "A breed of Northern African horses with high stamina and hardiness. Their generally hot temperament makes it harder to tame.",
"children": []
}
]
}
]
};
var treePlugin = new d3.mitchTree.boxedTree()
.setData(data)
.setElement(document.getElementById("visualisation"))
.setMinScale(0.5)
.setAllowZoom(false)
.setIdAccessor(function(data) {
return data.id;
})
.setChildrenAccessor(function(data) {
return data.children;
})
.setBodyDisplayTextAccessor(function(data) {
return data.description;
})
.setTitleDisplayTextAccessor(function(data) {
return data.name;
})
.initialize();
</script>
Chain this method before .initialize():
.on("nodeClick", function(event, index, arr) {
if (!event.data.children.length) {
console.log('you clicked a child-less item', event.data);
}
})
Inside the condition, event.data is the clicked childless item. Feel free to place URLs inside those objects and use those URLs to navigate away.
Taken from the repo's /examples folder, where I found one named Advanced example with Node Click Event.
According to the comment on the same page, you can also achieve this using the options syntax:
/* const tree = [
place your data here...
]; // */
new d3.mitchTree.boxedTree({
events: {
nodeClick({ data }) {
if (!data.children.length) {
console.log('You clicked a childless item', data);
}
}
}
})
.setData(tree)
// ...rest of chain
.initialize();

How to output JSON data, from an external API, in jQuery like I see it in the console log, in HTML (formatting JSON in jQuery)

Edit: I've had some luck with
var items = [];
$.each(response.response.content, function(i, item) {
$("#title").append(item.title + " ");
});
I've connected to an external API and can get everything printed out perfectly in my console log, but can only print it out in JSON format on my HTML page. I'm baffled as to why I can't figure out how to get it to print the same way on my page.
<script>
const settings = {
"async": true,
"crossDomain": true,
"url": "https://learning-objects-v2.p.rapidapi.com/search?keywords=Excel&lang=en&type=video&sort=popularity&model=strict&max=10&page=0",
"method": "GET",
"headers": {
"x-rapidapi-key": "12345678901234567890",
"x-rapidapi-host": "learning-objects-v2.p.rapidapi.com"
}
};
$.ajax(settings).done(function (response) {
$('#demo').append(JSON.stringify(response))
var items = [];
$.each(response.response.content, function(i, item) {
console.log(item);
});
});
</script>
And here is some of the JSON
"response":{
"content":[
{
"title":"Normal distribution excel exercise | Probability and Statistics | Khan
Academy",
"url":"https://www.youtube.com/watch?v=yTGEMoaWDCQ",
"description":"(Long-26 minutes) Presentation on spreadsheet to show that the normal distribution approximates the binomial distribution for a large number of trials. Watch the next lesson: https://www.khanacademy.org/math/probability/statistics-inferential/normal_distribution/v/ck12-org-normal-distribution-probl...",
"picture":"https://i.ytimg.com/vi/yTGEMoaWDCQ/hqdefault.jpg",
"provider":[
"YouTube"
],
"bloom":[
"discover"
],
"type":[
"Video"
],
"level":-0.5,
"learningTimeValue":26.07,
"learningTimeUnit":"min"
Here is an example of the console log
{title: "Excel Forecast Function Explained!", url: "https://www.youtube.com/watch?v=nRrZJpG_S7M", description: "This excel video tutorial provides a basic introdu…ted sales forecast in the future. My Website: ...", picture: "https://i.ytimg.com/vi/nRrZJpG_S7M/hqdefault.jpg", provider: Array(1), …}
bloom: ["discover"]
description: "This excel video tutorial provides a basic introduction into the forecast function which can be used to predict a y value given an x value. It could be used to predict the population at a certain year, the value of a car at a given time, or the estimated sales forecast in the future. My Website: ..."
learningTimeUnit: "min"
learningTimeValue: 10.3
level: -0.5
picture: "https://i.ytimg.com/vi/nRrZJpG_S7M/hqdefault.jpg"
provider: ["YouTube"]
title: "Excel Forecast Function Explained!"
type: ["Video"]
url: "https://www.youtube.com/watch?v=nRrZJpG_S7M"
I know I need to assign 's to it, and put it into a loop, but I'm not sure exactly how, and the books I have open aren't helping much. Thank you kindly!
You just need to use keyname to access required values i.e : title,pictures..etc .So , inside your each loop get that values and add them inside generated html and finally append this to your DOM.
Demo Code :
//just for demo ..suppose response variable have your response :
var response = {
"response": {
"content": [{
"title": "Normal distribution excel exercise | Probability and Statistics | Khan Academy ",
"url": "https://www.youtube.com/watch?v=yTGEMoaWDCQ",
"description": "(Long-26 minutes) Presentation on spreadsheet to show that the normal distribution approximates the binomial distribution for a large number of trials. Watch the next lesson: https://www.khanacademy.org/math/probability/statistics-inferential/normal_distribution/v/ck12-org-normal-distribution-probl...",
"picture": "https://i.ytimg.com/vi/yTGEMoaWDCQ/hqdefault.jpg",
"provider": [
"YouTube"
],
"bloom": [
"discover"
],
"type": [
"Video"
],
"level": -0.5,
"learningTimeValue": 26.07,
"learningTimeUnit": "min",
}, {
"title": "Normal distribution excel exercise | Probability and Statistics | Khan Academy2222 ",
"url": "https://www.youtube.com/watch?v=yTGEMoaWDCQ",
"description": "(Long-26 minutes) Presentation on spreadsheet to show that the normal distribution approximates the binomial distribution for a large number of trials. Watch the next lesson: https://www.khanacademy.org/math/probability/statistics-inferential/normal_distribution/v/ck12-org-normal-distribution-probl...",
"picture": "https://i.ytimg.com/vi/yTGEMoaWDCQ/hqdefault.jpg",
"provider": [
"YouTube"
],
"bloom": [
"discover"
],
"type": [
"Video"
],
"level": -0.5,
"learningTimeValue": 26.07,
"learningTimeUnit": "min",
}]
}
}
var html = ""
$.each(response.response.content, function(i, item) {
//just for demo ..
html += `<div><img src="${item.picture}"/>${item.title}</div>`
});
$("#somediv").html(html)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<div id="somediv"></div>

How can I improve my search function Logic? Using Lunr.js

So I am using Lunr.js for my search function. Everything is working nice and dandy BUT, when I search certain keywords like "God" and "church" I get unacceptably long search times. I mean like, 30 secs and even beyond 1 min long. I'm sure it must be the logic I am using that is causing this, at least I think it is. The aim of my Search Function is to search the users input and return only the sentences where the key word is found along with the name of the book and the page where the searchQuery is found. My goal is to have a search function that can work offline. This is a Cordova project. I have commented everything so that you can follow the logic easily. Thank you for your time and input!
function searchFunction() {
//Clears results-wrapper Html element
document.querySelector(".results-wrapper").innerHTML = "";
//Store query in localDB
searchQuery = document.querySelector("#search-id").value;
localStorage.setItem("searchQuery", searchQuery);
//Returns from the index only the books which contains the query
var results = idx.search(searchQuery);
//Run through "results" and return all the text where the query is found
results.forEach(function (entry) {
//documents contains the database of all the books from my json file
documents.find(findSearchQuery);
//Searches only the text of the doc/books found in results variable
function findSearchQuery(doc) {
//searchQuery is the users input
let re = new RegExp(searchQuery, "i");
//if the book's name matches reference in "results"
if (doc.name == entry.ref) {
//And if the searchQuery is found in Books text
if (doc.text.match(re)) {
//Break up the block of text into sentences
var sentences = doc.text.match(/[^\.!\?]+[\.!\?]+/g);
sentences.forEach(function (sentence) {
//Find the sentence inside the sentences array and return the one with the searchQuery
//Populate HTML element "results-wrapper" with the results
if (sentence.match(re)) {
var anchor = document.createElement("a");
anchor.className = "anchorSearchResult";
anchor.href = doc.href;
//Create "div" element
var div = document.createElement("div");
div.className = "div-test";
//Creates "h4" element for title
var h4 = document.createElement("h4");
var title = document.createTextNode(doc.name);
h4.className = "title-results";
//Creates "p" element for sentence
var textElement = document.createElement(p);
var searchResult = document.createTextNode(sentence);
textElement.className = "text-results";
//Creates "p" element for page
var p = document.createElement("p");
var pageResult = document.createTextNode(doc.page);
p.className = "page-results";
h4.appendChild(title);
textElement.appendChild(searchResult);
p.appendChild(pageResult);
div.appendChild(h4);
div.appendChild(textElement);
div.appendChild(p);
anchor.appendChild(div);
document.querySelector(".results-wrapper").appendChild(anchor);
anchor.addEventListener("click", returnSearchResultId);
function returnSearchResultId(e) {
//store selectorId value of document
localStorage.setItem("selectorId", doc.selectorId);
}
// Highlight Function
var instance = new Mark(
document.querySelector(".results-wrapper")
);
instance.mark(searchQuery, {
element: "span",
className: "highlight",
});
}
});
}
}
}
});
}
And here is just a snippet of my json file that is loaded in my "documents" variable.
[
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "Pre-\"Eleventh Hour\" Extra MYSTERY OF MYSTERIES EXPOSED!",
"page": "1TR 2",
"href": "tracks/tr1.html#page-2.subHeading",
"selectorId": "#page-2\\.subHeading"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "In the interest of reaching every truth-seeking mind that desires to escape the path that leads to destruction of both body and soul, this tract will be distributed free of charge as long as this issue lasts.",
"page": "1TR 2",
"href": "tracks/tr1.html#page-2.1",
"selectorId": "#page-2\\.1"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "PREFACE PERSONALLY WATCHING FOR EVERY RAY OF LIGHT.",
"page": "1TR 3",
"href": "tracks/tr1.html#page-3.preface",
"selectorId": "#page-3\\.preface"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "One who entrusts to another the investigation of a message from the Lord, is making flesh his arm, and thus is foolishly acting as without a mind of his own. And ”the mind that depends upon the judgment of others is certain, sooner or later, to be misled. ” -- Education, p. 231.",
"page": "1TR 3",
"href": "tracks/tr1.html#page-3.1",
"selectorId": "#page-3\\.1"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "Similarly, one who allows prejudice to bar him from a candid investigation of anything new, coming in the name of the Lord, is unwittingly an infidel.",
"page": "1TR 3",
"href": "tracks/tr1.html#page-3.2",
"selectorId": "#page-3\\.2"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "Likewise he who is satisfied with his present attainments in the Word of God, says in effect: \"I am rich, and increased with goods, and have need of nothing.",
"page": "1TR 3",
"href": "tracks/tr1.html#page-3.3",
"selectorId": "#page-3\\.3"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "All these, in variously acting out the part which provoked the condemnation written against the Laodiceans, thereby fulfilling the prophecy which they ought not fulfill, are preparing themselves to be spued out (Rev. 3:14-18). And if they continue in their self-satisfied attitude that they have all the truth, and so have need of nothing more, they will spurn every new claimant to truth and toss the message into the discard because it comes through an unexpected channel. Certainly, then, were this tract not the unfolding of prophecy, the fact is inevitable that when the unfoldment did come, they would treat it in like manner, and consequently toss away their salvation!",
"page": "1TR 3",
"href": "tracks/tr1.html#page-3.4",
"selectorId": "#page-3\\.4"
},
{
"name": "Pre-Eleventh-Hour Extra",
"year": "1941",
"text": "Throughout the ages, all who have put their trust in the so-called wise men, and foremost Christians of the day, all reputedly godly men, have by these very ones been bereft of the crown of eternal life, as were the Jewish laity in the days of Christ because of their failing to assume full responsibility for their own salvation. Presumptuously trusting in the wisdom of their so-called \"great men,\" they declined to believe in Christ's words \"O Father, Lord of heaven and earth,...Thou hast hid these things from the wise and prudent, and hast revealed them unto babes.\" Matt. 11:25 \"Where is the wise? where is the scribe?...hath not God made foolish the wisdom of this world?\" 1 Cor 1:20.",
"page": "1TR 4",
"href": "tracks/tr1.html#page-4.1",
"selectorId": "#page-4\\.1"
}
]
Figured it out! It was the highlight functionality that I am getting from the Mark.js library that was causing the huge delay. After commenting it out, everything is lightening fast again.

Is it possible to get a list of all items in an array of objects that match items in another array?

I'm working on a React project that'll allow me to search through a list of games to help me decide what to play based on what I'm in the mood for, currently I can add games to a JSON file but I'm really struggling with the searching part.
Right now, to add a new game, you'll enter the title, genre(s) and a description of the game. The genre field is a ReduxForm FieldArray object, and I think that's what's giving me the trouble. Here's my current JSON file
{
"games": [
{
"name": "Rainbow Six: Siege",
"genres": [
{
"genre": "tactical"
},
{
"genre": "shooter"
}
],
"description": "tactical team based shooter",
"id": 1
},
{
"name": "Resident Evil 2",
"genres": [
{
"genre": "horror"
},
{
"genre": "survival"
},
{
"genre": "shooter"
}
],
"description": "classic resident evil 2 remake in 2019",
"id": 2
},
{
"name": "Rocket League",
"genres": [
{
"genre": "cars"
},
{
"genre": "competition"
},
{
"genre": "one more game"
}
],
"description": "soccar!",
"id": 3
}
]
}
This is the dummy data I'm using to search:
const searchedGenres = 'horror, shooter';
const searchedList = searchedGenres.split(', ');
let foundGame = [];
Once I get the search working with this data, the plan is to allow me to just type in data on the frontend in one textbox, so "horror, shooter" would be my search term. The result from this search should only return Resident Evil 2, however I'm also receiving Rainbow Six: Siege as a result, even though it's missing one of my requested genres.
searchedList.forEach(searchedGenre => {
this.props.games.map(game => {
if (
game.genres.find(
({ genre }) =>
genre.toLowerCase() ===
searchedGenre.toLowerCase().trim()
) !== undefined
) {
foundGames.push(game);
}
});
});
I understand why I'm getting both Rainbow Six and Resident Evil as a result, because I'm not actually checking that both genres are in the games genres when I add the game to the foundGames array, but I'm completely lost on how I'd go about making sure all of the genres are in a game before I add it.
This would be a bit easier if your genres was a simple array of strings rather than objects, but still you can check pretty succinctly by leveraging some() and every() within filter() (btw filter() is a better choice than map() + push() here)
let games = [{"name": "Rainbow Six: Siege","genres": [{"genre": "tactical"},{"genre": "shooter"}],"description": "tactical team based shooter","id": 1},{"name": "Resident Evil 2","genres": [{"genre": "horror"},{"genre": "survival"},{"genre": "shooter"}],"description": "classic resident evil 2 remake in 2019","id": 2},{"name": "Rocket League","genres": [{"genre": "cars"},{"genre": "competition"},{"genre": "one more game"}],"description": "soccar!","id": 3}]
const searchedGenres = 'horror, shooter';
const searchedList = searchedGenres.split(', ');
let foundGame = games.filter(game => searchedList.every(searchItem => game.genres.some(g => g.genre == searchItem) ))
console.log(foundGame)
The filter condition basically says you want every game in searchedList to match at least one genre in the game. This will make it only return games that match every genre.

Put JSON data with the same name into different divs

I have JSON file with this structure:
{
"launches": [{
"name": "First Name"
}],
"launches": [{
"name": "Second Name"
}],
"launches": [{
"name": "Third Name"
}],
"launches": [{
"name": "Fourth Name"
}]
}
I add the data like this:
$('#div-name').append(d.name);
When this is displayed on a webpage, it is placed in one div with no spaces. I can add a <p> tag to the append, but that still displays ALL the data and creates new divs to display it.
Basically, what I am trying to do is to create a div for each separate "name" value and display only one value per div.
First of all, your "json" is not a valid json, remmeber that in a json object, you can not have duplicated keys. You can easily use an online validator to help you with that... and after you fix it, let's assume that what you actually have is an array of objects like:
[
{"name": "Falcon 9"},
{"name": "Orion"},
{"name": "PSLV"},
{"name": "Soyuz"}
]
with this valid json, you can easily loop trough all the elements like (and take that you are using jQuery):
var json = [ ... ];
$(function() {
$.each(json, function(i, item){
$("p").append("<div>" + item.name + "</div>");
});
});
here's a live test: https://jsbin.com/bixadegeye/1/edit?html,css,js,output
A slightly different way of going about it:
var data = {
"names": [
"Falcon 9",
"Orion",
"PSLV",
"Soyuz"
]
};
$.each( data["names"], function( key, value ) {
$('#div-name').append(value+"<br />");
});

Categories

Resources