Accept accent marks & ñ on javascript - javascript

I'm making a bot that answers questions given some key words. It's a very easy code developed by Deni Spasovski. However, my website is in Spanish, and I need to be able to use accent marks & ñ as part of the key words. For example:
{ "keys": ["cómo", "estás"], "value": 0 }
However, despite my efforts, I can't seem to fix the code. I don't know that much about coding. Maybe it's a very easy thing I have to implement to one of the scripts but I really do not know what it is.
I would be more than grateful if you could help me.
Thank you very, very much in advance!!
This is the HTML:
<!DOCTYPE html>
<html>
<head>
<!--Read the source Luke!-->
<title>Answer bot</title>
<style type="text/css">
body, html
{
height: 100%;
}
.wrap
{
height: 80%;
overflow: auto;
max-height: 80%;
display: block;
}
.content
{
height: 100%;
display: table;
vertical-align: bottom;
}
.subcontent
{
display: table-cell;
vertical-align: bottom;
}
.answerbot-input
{
color: #1AA1E1;
}
.answerbot-ai
{
color: #CE5043;
}
</style>
</head>
<body>
<div style="width: 800px; height: 100%; margin: 0 auto;">
<div id="wrap" class="wrap">
<div class="content">
<div class="subcontent" id='subcontent'>
<p class='answerbot-ai'>
Don't be afraid, talk to me.
</p>
</div>
</div>
</div>
<div>
<input type="text" name="inputtext" style="width: 100%;" onkeyup="keypressInput(this, event);"><br />
</div>
</div>
<script type="text/javascript" src="scripts.js"></script>
<script type="text/javascript" src="data.js"></script>
<script type="text/javascript">
var _answerBot = new answerBot();
function keypressInput(sender, event) {
if (event.which == 13) {
document.getElementById('subcontent').innerHTML += _answerBot.processInput(sender.value);
sender.value = '';
correctScroll("wrap");
}
}
function correctScroll(elementId) {
var objDiv = document.getElementById(elementId);
objDiv.scrollTop = objDiv.scrollHeight;
}
</script>
</body>
</html>
This is the data.js:
if (answerBot) {
answerBot.prototype.specialContext = {
"wrongInput": ["I don't understand you.", "Could you rephrase the question?"],
"emptyInput": ["Please say something", "Speak louder", "Well i can't read minds."],
"rephrase": ["Can you tell me if your question was about one of the following things:"]
};
answerBot.prototype.keywords = [
{ "keys": ["hi"], "value": 0 },
{ "keys": ["hello"], "value": 0 },
{ "keys": ["life", "universe", "everything"], "value": 1 },
{ "keys": ["software", "development"], "value": 2 },
{ "keys": ["software", "engineering"], "value": 2 },
{ "keys": ["who", "made", "you"], "value": 3 },
{ "keys": ["who", "wrote", "you"], "value": 3 },
{ "keys": ["who", "coded", "you"], "value": 3 },
{ "keys": ["is", "this", "real", "life"], "value": 4 },
{ "keys": ["who", "is", "deni"], "value": 5 },
{ "keys": ["tell", "me", "about", "deni"], "value": 5 },
{ "keys": ["tell", "me", "about", "author"], "value": 5 },
{ "keys": ["show", "me", "author"], "value": 5 },
{ "keys": ["can", "see", "source"], "value": 6 },
{ "keys": ["can", "see", "sourcecode"], "value": 6 },
{ "keys": ["show", "me", "code"], "value": 6 },
{ "keys": ["how", "are", "you"], "value": 7 },
{ "keys": ["who", "is", "this"], "value": 8 }];
answerBot.prototype.answers = [
{
"description": "Hi!",
"values": ["Hello there!", "Hi how can I help you today", "Hi! What brings you here?"]
},
{
"description": "What is the answer to life the universe and everything?",
"values": ["42"]
},
{
"description": "What is software development?",
"values": ["Programming! Do you speak it?"]
},
{
"description": "Who created me?",
"values": ["I was created by another <a href='http://about.me/deni' target='_blank'>bot</a>.", "The question is who sent you here?"]
},
{
"description": "Is this real life?",
"values": ["No this is the internetz!", "Find out <a href='http://www.youtube.com/watch?v=txqiwrbYGrs' target='_blank'>yourself</a>!"]
},
{
"description": "Who is Deni?",
"values": ["This is his <a href='https://plus.google.com/+DeniSpasovski/' target='_blank'>G+ profile</a>.", "This is his <a href='www.linkedin.com/in/denispasovski' target='_blank'>Linkedin profile</a>."]
},
{
"description": "Where is your source?",
"values": ["Here is the <a href='https://github.com/denimf/Answer-bot' target='_blank'>source</a>."]
},
{
"description": "How are you?",
"values": ["I'm good how are you?"]
},
{
"description": "Who is this?",
"values": ["StackOverflow Exception occurred", "The question is who are you?"]
}
];
}
And this is the scripts.js:
var answerBot = function () {
var _this = this;
_this.processInput = function (text) {
updateUrl(text);
var _result = "<p class='answerbot-input'>" + text + "</p>";
text = text.replace(new RegExp("[^a-zA-Z ]", "g"), " ");
text = text.replace(new RegExp("[ ]{2,}", "g"), " ");
var _words = text.toLowerCase().split(" ");
var _answers = [];
var _title = "";
if (_words.length === 0 || _words.toString() === '') { //if the input is empty
_answers = _this.specialContext.emptyInput;
_title = _this.specialContext.emptyInput;
} else {
var _possibleAnswers = findMatches(_words);
if (_possibleAnswers.length === 0) { //if no answer found
_answers = _this.specialContext.wrongInput;
_title = _this.specialContext.wrongInput;
}
if (_possibleAnswers.length == 1) { //context recognized
_answers = _this.answers[_possibleAnswers[0]].values;
_title = _this.answers[_possibleAnswers[0]].description;
}
if (_possibleAnswers.length > 1) {
_result += formatText(_this.specialContext.rephrase, _this.specialContext.rephrase);
for (var i = 0; i < _possibleAnswers.length; i++) {
_result += formatText(_this.answers[_possibleAnswers[i]].description, _this.answers[_possibleAnswers[i]].description);
}
}
}
if (_answers.length > 0) {
var _rand = Math.floor((Math.random() - 0.001) * _answers.length);
_result += formatText(_answers[_rand], _title);
}
return _result;
};
function formatText(text, title) {
return "<p class=\'answerbot-ai\' title=\'" + title + "\'>" + text + "</p>";
}
function findMatches(words) {
var foundKeywords = [];
var _possibleAnswers = [];
for (var i = 0; i < _this.keywords.length; i++) {
foundKeywords[i] = 0;
for (var j = 0; j < words.length; j++) {
if (_this.keywords[i].keys.indexOf(words[j]) >= 0) {
foundKeywords[i]++;
if (foundKeywords[i] == _this.keywords[i].keys.length) {
return [_this.keywords[i].value];
}
}
}
if (foundKeywords[i] * 2 > _this.keywords[i].keys.length) {
_possibleAnswers.push(_this.keywords[i].value);
}
}
return _possibleAnswers.filter(function (elem, pos) {
return _possibleAnswers.indexOf(elem) == pos;
});
}
function updateUrl(text){
history.pushState(null, null, "#question=" + encodeURIComponent(text));
if(typeof ga === "function")//google analytics
ga('send', 'event', 'question', text);
}
};

Three possible issues:
1) This line:
text = text.replace(new RegExp("[^a-zA-Z ]", "g"), " ");
will replace anything that isn't in the "normal" alphabet with a space. You might choose to replace it at some point to include characters with diacritics, but to get it working you can simply comment it out.
2) Make sure your files (in particular, data.js) are saved with UTF-8 encoding.
3) Ensure you have an appropriate value in the answers array and then use its index in keywords.value. e.g.
{
"description": "cómo estás?",
"values": ["muy bien"]
}

Related

How to correct logic in a search input? Angular

I have a search input in my angular application that should compare the input data with different object properties
<div class="forms">
<div class="search-wrapper">
<input
class="search"
[ngClass]="{'searching': searching}"
type="text"
(input)="changeSearch($event.target.value)"
/>
<label class="">
<span>Rechercher</span>
</label>
</div>
</div>
the logic I use is as follows
public changeSearch(searchTerm: string) {
this.searching = !!searchTerm;
if (!this.searching) {
this.orders.forEach(order => {
order.show = true;
});
return;
}
const extendSearchIn = ['order_number', 'transaction.item.product.name'];
this.orders.forEach(order => {
order.show = true;
extendSearchIn.forEach(property => {
this.searchByProperty(order, property, searchTerm);
});
});
}
public searchByProperty(order, property, searchTerm) {
const prop = this.getSearchProperty(order, property);
if (prop === undefined) { return false; }
return (<String>prop.toLowerCase()).startsWith(searchTerm.toLowerCase());
}
public getSearchProperty(item: object, property: string) {
let itemCopy = Object.assign({}, item);
let result: any;
const props = property.split('.');
props.forEach(prop => {
if (itemCopy !== undefined) {
itemCopy = itemCopy[prop];
}
});
result = itemCopy !== undefined ? itemCopy : result;
return result;
}
and the structure of each object 'order' is like the following
{
"functional_id": "202006101058160012400000SD4AYAA1",
"transactions": [
{
"quantity": 2,
"price": 140,
"item": {
"name": "Carton",
"description": "+ 2 recharges",
"product": {
"name": "Coffret rouge"
}
},
"amount": 280
},
{
"quantity": 2,
"price": 140,
"item": {
"name": "10 coffrets",
"description": "+ 2 recharges",
"product": {
"name": "Coffret gris"
}
},
"amount": 280
},
{
"quantity": 2,
"price": 60,
"item": {
"name": "PACK N°1 comprenant :",
"description": "6 modèles",
"product": {
"name": "AfuBOX",
"description": "60,8 x 39,5 x 16,5 cm"
}
},
"amount": 120
}
],
"show": true,
"date": "10/06/2020",
"order_number": "105816",
"overallAmount": 680
}
you would need to set the 'show' property to false so that those that don't comply with what was entered in the search field would be hidden
Someone to make me see where my mistake is.
Thank you in advance
I have simplified the logic with a forEach and checking if the value I receive from the input contains any of the search criteria I wanted to apply.
I hope that this will help you to explain if you find yourself in a similar situation.
public changeSearch(searchTerm: string) {
this.searching = !!searchTerm;
if (!this.searching) {
this.orders.forEach(order => {
order.show = true;
});
return;
}
this.orders.forEach(order => {
order.show = true;
this.searchByProperty(order, searchTerm);
});
}
public searchByProperty(order, searchTerm) {
const id = (order.order_number + '');
const amount = (order.overallAmount + '');
order.transactions.forEach(items => {
const title = items.item.product.name.toLowerCase();
if (title.includes(searchTerm) || id.includes(searchTerm) || amount.includes(searchTerm)) {
order.show = true;
} else {
order.show = false;
}
});
}

Trying to access json content and display in a grid fashion

I have a JSON file having the following content.
{
"rooms":[
{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [
{
"srcname":["DirectTV","AppleTV","Sonos"],
"iconpath":["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png","path2"]
}
],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [
{
"srcname":["Climate","Shades"],
"iconpath":["path1","path2"]
}
],
"hex": "#000"
}
}
]
}
My HTML file Has:
<div class="roww">
<div class="col-md-4 col-sm-6 col-12">
</div>
</div>
I want to display my JSON content in the HTML.
So far I have tried the following.
private initTileGrid():void
{
var col = document.getElementsByClassName("roww")[0];
var outeritems=this.room_list.rooms;
// console.log(outeritems);
for(var i=0;i<outeritems.length;i++){
var tile = document.getElementsByClassName("col-md-4 col-sm-6 col-12 tile no-padding")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
var inneritem=outeritems[i].Settings.Sources.srcname;
console.log(inneritem);
var innerdiv = document.createElement("div");
for(var j=0;j<inneritem.length;j++)
{
console.log("hi")
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem.srcname;
console.log(h5inner);
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
}
I am able to display the description and name from the json but not able to fetch the list of sources.
My final solution should be a grid with number of tiles equal to the number of objects in the JSON, with each tile having a background image from the json and its content.
Can anybody tell me where I am going wrong?
Any help appreciated!
I would suggest and recommend generating your dynamic HTML the following way with Template Literals.
Using Array#map, Array#join and Destructuring assignment
const data = {"rooms":[{"id":"1","name":"living","Description":"The living room","backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw","Settings":{"Sources":[{"srcname":["DirectTV","AppleTV","Sonos"],"iconpath":["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png","path2"]}],"hex":"#000"}},{"id":"2","name":"dining","Description":"The Dining room","backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV","Settings":{"Sources":[{"srcname":["Climate","Shades"],"iconpath":["path1","path2"]}],"hex":"#000"}}]}
const res = data.rooms.map(({name, Description, Settings:{Sources}})=>{
const inner = Sources.map(({srcname})=>{
return srcname.map(src=>`<h5>${src}</h5>`).join("");
}).join("");
return `
<div>
<h5>${Description}</h5>
<p>${name}</p>
<div class="inner">
${inner}
</div>
</div>
`
}).join("");
document.body.innerHTML = res;
body>div{background-color:lightgrey;padding:5px;margin-top:5px}body>div::before{content:"row"}body>div>*{margin-left:10px}h5{background-color:blue;color:white;padding:5px}h5::before{content:"outer h5:: "}p{background-color:purple;color:white;padding:5px}p::before{content:"p:: "}div.inner{padding:5px;background-color:grey}div.inner::before{content:"inner div"}div.inner>h5{background-color:green;color:white}div.inner>h5::before{content:"inner h5:: "}
Unminified CSS:
body > div {
background-color: lightgrey;
padding: 5px;
margin-top: 5px;
}
body > div::before {
content: "row";
}
body > div > * {
margin-left: 10px;
}
h5 {
background-color: blue;
color: white;
padding: 5px;
}
h5::before {
content: "outer h5:: "
}
p {
background-color: purple;
color: white;
padding: 5px;
}
p::before {
content: "p:: ";
}
div.inner {
padding: 5px;
background-color: grey;
}
div.inner::before {
content: "inner div";
}
div.inner > h5 {
background-color: green;
color: white;
}
div.inner > h5::before {
content: "inner h5:: "
}
V_Stack as discussed, this is just the tweak I would do to the sources section of the JSON, moving forward it will make working with a source easier, especially if you add additional properties. Note it is an array of self contained objects now.
{
"rooms": [{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [{
"srcname": "DirectTV",
"iconpath": "src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png"
},
{
"srcname": "AppleTV",
"iconpath": "path2"
},
{
"srcname": "Sonos",
"iconpath": ""
}
],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [{
"srcname": "Climate",
"iconpath": "path1"
},
{
"srcname": "Shades",
"iconpath": "path2"
}
],
"hex": "#000"
}
}
]
}
Try this:
var col = document.getElementsByClassName("roww")[0];
var outeritems = this.room_list.rooms;
// console.log(outeritems);
for (var i = 0; i < outeritems.length; i++) {
var tile = document.getElementsByClassName("col-md-4")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
outeritems[i].Settings.Sources.forEach(source => {
var inneritem = source.srcname;
console.log(inneritem);
var innerdiv = document.createElement("div");
for (var j = 0; j < inneritem.length; j++) {
console.log("hi")
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem[j];
console.log(h5inner);
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
});
}
}
You need to loop through the Settings.Sources and srcname because all of them are arrays
Your main problem starts at this line var inneritem=outeritems[i].Settings.Sources.srcname; Sources is an array so you need to access it like Sources[j] where j is a number within the arrays length.
The inner loop is fine, you just need to loop through Sources properly
I also had to add classes to the tiles class to match your getElementsByClassName query
const room_list = {
"rooms": [{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [{
"srcname": ["DirectTV", "AppleTV", "Sonos"],
"iconpath": ["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png", "path2"]
}],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [{
"srcname": ["Climate", "Shades"],
"iconpath": ["path1", "path2"]
}],
"hex": "#000"
}
}
]
}
var col = document.getElementsByClassName("roww")[0];
var outeritems = room_list.rooms;
// console.log(outeritems);
for (var i = 0; i < outeritems.length; i++) {
var tile = document.getElementsByClassName("col-md-4 col-sm-6 col-12 tile no-padding")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
var inneritems = outeritems[i].Settings.Sources
var innerdiv = document.createElement("div");
for (var j = 0; j < inneritems.length; j++) {
var inneritem = inneritems[j];
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem.srcname;
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
}
<div class="roww">
<div class="col-md-4 col-sm-6 col-12 tile no-padding">
</div>
</div>

How can one iterate with this JSON response file

As said above, I don't know how to use this kind of JSON response from my server-side php which I got by using this code echo json_encode(array_merge($outp, $outp2));
[
{
"stuid":"12",
"stuname":"Velino Meratis",
"stucourse":"BSIT",
"stustat":"0",
"stulyear":"4",
"stulog":"feb 16 2017"
},
{
"stuid":"13",
"stuname":"Alana Melker",
"stucourse":"BSCE",
"stustat":"1",
"stulyear":"5",
"stulog":"feb 16 2017"
},
{
"stuid":"12",
"cname":"InfoTech000",
"clog":"1"
},
{
"stuid":"12",
"cname":"InfoTech001",
"clog":"2"
},
{
"stuid":"12",
"cname":"C101",
"clog":"3"
},
{
"stuid":"13",
"cname":"CE000",
"clog":"4"
},
{
"stuid":"13",
"cname":"CE001",
"clog":"5"
},
{
"stuid":"13",
"cname":"C101",
"clog":"6"
}
]
If I use this code in my client side javascript
if (this.readyState == 4 && this.status == 200) {
students = JSON.parse(this.responseText);
students.forEach(function(item){
console.log(item.stuid);
x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.cname + "<br>";
});
}
it just ends up giving me this:-
12 Velino Meratis
undefined
13 Alana Melker
undefined
Somehow I can iterate the stuid and the stunamebut it won't allow them to contain the cname as an array with them.
How can I turn that into something like this:-
12 Velino Meratis
InfoTech000, InfoTech001, C101
13 Alana Melker
CE000, CE001, C101
Can someone Help and Elaborate on this?
You can check if the array contains the key or not, that way you will be saved from "undefined" error.
You can do it this way
if(item.hasOwnProperty('cname'))
{
console.log(item.cname);
}
You can use this for stuname or other keys also.
You need to merge student objects in your array by unique IDs. One way to do this is to add new stuids to an array and merge it with subsequent items with same stuid. Once you have array of unique students, you can proceed with other goals.
if (this.readyState == 4 && this.status == 200) {
var students_raw = JSON.parse(this.responseText);
var students = [];
students_raw.forEach(function(item){
var existing = students.find($item => item.stuid === $item.stuid);
if (existing) {
existing = Object.assign({}, existing, item);
} else {
students.push(item);
}
});
// your print loop
students.forEach(function(item) {
var x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.cname + "<br>";
});
}
Please note: Array.reduce() and Object.assign() are not supported widely. you may need to polyfill these methods
NOTE: This answer assumes you're willing and able to change the data coming from PHP
Credit where credit is due, this is an extension of #Magnus Eriksson's comment.
It would be preferable to keep the relevant data associated with each other. You should get better flexibility with well-formed data. Ideally, you should do this server side and present the data to the client already well formatted.
You should try and achieve something similar to the following for your output:
[{
"stuid": "12",
"stuname": "Velino Meratis",
"stucourse": "BSIT",
"stustat": "0",
"stulyear": "4",
"stulog": "feb 16 2017",
"classes": [{
"cname": "InfoTech000",
"clog": "1"
}, {
"cname": "InfoTech001",
"clog": "2"
}, {
"cname": "C101",
"clog": "3"
}]
}, {
"stuid": "13",
"stuname": "Alana Melker",
"stucourse": "BSCE",
"stustat": "1",
"stulyear": "5",
"stulog": "feb 16 2017",
"classes": [{
"cname": "CE000",
"clog": "4"
}, {
"cname": "CE001",
"clog": "5"
}, {
"cname": "C101",
"clog": "6"
}]
}];
Note I've used classes as the property name as it appears we are working with Courses and their classes.
Your javascript will now look like:
if (this.readyState == 4 && this.status == 200) {
students = JSON.parse(this.responseText);
students.forEach(function(item){
console.log(item.stuid);
x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.classes.map(function(elem){
return elem.cname;}).join(",") + "<br>";
});
}
Note the map function won't work in IE8 and lower.
Now for a working example:
var students = [{
"stuid": "12",
"stuname": "Velino Meratis",
"stucourse": "BSIT",
"stustat": "0",
"stulyear": "4",
"stulog": "feb 16 2017",
"classes": [{
"cname": "InfoTech000",
"clog": "1"
}, {
"cname": "InfoTech001",
"clog": "2"
}, {
"cname": "C101",
"clog": "3"
}]
}, {
"stuid": "13",
"stuname": "Alana Melker",
"stucourse": "BSCE",
"stustat": "1",
"stulyear": "5",
"stulog": "feb 16 2017",
"classes": [{
"cname": "CE000",
"clog": "4"
}, {
"cname": "CE001",
"clog": "5"
}, {
"cname": "C101",
"clog": "6"
}]
}];
students.forEach(function(item){
console.log(item.stuid);
x = item.stuid;
document.getElementById("demo").innerHTML += x + " " + item.stuname + "<br>" + item.classes.map(function(elem){
return elem.cname;}).join(",") + "<br>";
});
<div id="demo"></div>
As mentioned in other answers and comments, the issue with your existing code, is not all objects in your json array have the property you're referencing.
You can try like this once also
HTML
<div id="result"></div>
SCRIPT
var dataJSON = [
{
"stuid":"12",
"stuname":"Velino Meratis",
"stucourse":"BSIT",
"stustat":"0",
"stulyear":"4",
"stulog":"feb 16 2017"
},
{
"stuid":"13",
"stuname":"Alana Melker",
"stucourse":"BSCE",
"stustat":"1",
"stulyear":"5",
"stulog":"feb 16 2017"
},
{
"stuid":"12",
"cname":"InfoTech000",
"clog":"1"
},
{
"stuid":"12",
"cname":"InfoTech001",
"clog":"2"
},
{
"stuid":"12",
"cname":"C101",
"clog":"3"
},
{
"stuid":"13",
"cname":"CE000",
"clog":"4"
},
{
"stuid":"13",
"cname":"CE001",
"clog":"5"
},
{
"stuid":"13",
"cname":"C101",
"clog":"6"
}
] ;
var arr = {};
for(var i = 0 ; i< dataJSON.length ; i++){
var ele = dataJSON[i];
if(arr[ ele.stuid ]==undefined){
arr[ ele.stuid ] = {};
}
arr[ ele.stuid ]['stuid'] = ele.stuid;
if(ele.stuname!=undefined){
arr[ ele.stuid ]['stuname'] = ele.stuname;
}
if(arr[ ele.stuid ]['cname'] == undefined){
arr[ ele.stuid ]['cname'] = [];
}
if(ele.cname!=undefined){
arr[ ele.stuid ]['cname'].push(ele.cname);
}
}
var str = '';
for(var key in arr){
var obj = arr[key];
str += obj['stuid'] +" "+obj['stuname']+'<br/>';
str += obj['cname'].toString()+'<br/>';
}
document.getElementById("result").innerHTML = str;
Thanks,

Represent data from json file in rating stars without jquery!! pure javaScript

I am trying to load the data from my JSON file using javaScript and i need to represent the hotel2show.rating in form of stars, just represent them dependig on the value from 'hotels.json'
Here is my JavaScript
function getHotels(i){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
hotel=JSON.parse(xhr.responseText);
var hotel2show = hotel.hotels[i];
document.getElementById("img-container").innerHTML =
"<img src='"+hotel2show.imgUrl+"'>"+
"<p id='name'><strong>"+ hotel2show.name +"</strong></p>" +"<br/>" + "<p id='rating'><strong>"+ hotel2show.rating +"</strong></p>" +"<br/>" + "<br/>" +"<p id='price'><strong>"+ '£' +hotel2show.price +
"</strong></p>" + "<p id='text'><strong>"+ 'Total hotel stay' +"</strong></p>";
} else {
alert("Ha existido un error con el servidor");
}
}
};
xhr.open("GET",'hotels.json', true);
xhr.send();
and here is my html
<div class="container">
<div id="lista">
<ul>
<button onclick="getHotels(0)">Hotel Sunny Palms</button>
<button onclick="getHotels(1)">Hotel Snowy Mountains</button>
<button onclick="getHotels(2)">Hotel Windy Sails</button>
<button onclick="getHotels(3)">Hotel Middle Of Nowhere</button>
</ul>
</div>
<div class="banner-section" id="img-container">
</div>
and my hotels.json
"hotels": [
{
"name": "Hotel Sunny Palms",
"imgUrl": "imgs/sunny.jpg",
"rating": 5,
"price": 108.00
},
{
"name": "Hotel Snowy Mountains",
"imgUrl": "imgs/snowy.jpg",
"rating": 4,
"price": 120.00
},
{
"name": "Hotel Windy Sails",
"imgUrl": "imgs/windy.jpg",
"rating": 3,
"price": 110.00
},
{
"name": "Hotel Middle of Nowhere",
"imgUrl": "imgs/nowhere.jpg",
"rating": 4,
"price": 199.00
}
]
any help is appreciated
For example..if you have UTF-8 charset then this should perhaps be fine. The key is createElement function by which you can construct your DOM as you wish.
var hotels = [{
"name": "Hotel Sunny Palms",
"imgUrl": "imgs/sunny.jpg",
"rating": 5,
"price": 108.00
}, {
"name": "Hotel Snowy Mountains",
"imgUrl": "imgs/snowy.jpg",
"rating": 4,
"price": 120.00
}, {
"name": "Hotel Windy Sails",
"imgUrl": "imgs/windy.jpg",
"rating": 3,
"price": 110.00
}, {
"name": "Hotel Middle of Nowhere",
"imgUrl": "imgs/nowhere.jpg",
"rating": 4,
"price": 199.00
}];
buildRating(hotels);
function buildRating(data) {
data.forEach(function(v) {
createRatingElement(v.rating);
});
}
function createRatingElement(numberOfStars) {
var wrapper = document.createElement('div');
for (var i = 1; i <= 5; i++) {
var span = document.createElement('span')
span.innerHTML = (i <= numberOfStars ? '★' : '☆');
span.className = (i <= numberOfStars ? 'high' : '');
wrapper.appendChild(span);
}
document.getElementById('img-container').appendChild(wrapper);
}
span {
display: inline-block;
position: relative;
width: 1.2em;
height: 1.2em;
color: black;
}
.high {
color: rgb(217, 211, 0);
}
<div class="banner-section" id="img-container">
</div>
Also, jsfiddle: https://jsfiddle.net/md4708oq/
I assume you know how to parse out your ratings, right? If you are just displaying single star values (whole numbers), then you can just write out a class onto a span element where you would style it with CSS to change what the background image would be.
So, you could make it show 1-5 stars with 4 different images.
It's a solution; not the cleanest or most scalable, but it works for this situation.
So first off this is a nightmare.
Let's clean it up a bit?
var appendString = [];
appendString[0] = "<img src='"+hotel2show.imgUrl+"'>";
appendString[1] = "<p id='name'><strong>"+ hotel2show.name +"</strong></p><br/>";
switch(hotel2show.rating):
case(1):
appendString[2] = "<p id='rating' class='rating-1'><strong>";
break;
case(2):
appendStirng[2] = "<p id='rating' class='rating-2><strong>";
break;
//etc
appendString[3] = hotel2show.rating +"</strong></p>";
appendString[4] = "<br/><br/>";
appendString[5] = "<p id='price'><strong>'£'" + hotel2show.price + "</strong></p>";
appendString[6] = "<p id='text'><strong>"+ 'Total hotel stay' +"</strong></p>";
document.getElementById("img-container").innerHTML = appendString.join(' ');
Note: the switch statement syntax may be incorrect.
You will have to use AJAX calls to retrieve JSON data and then use pure javascript to parse the JSON data and use it to display your html accordingly. Let me know if this is what you are looking for i will help you out with the same.

Get the unique items - Handlebars

My JSON looks like this:
{
"features": [
{
"id": "belly",
"scenarios": [
{
"id": "belly;a-few-cukes",
"tags": [
{
"name": "#tag1"
}
],
"steps": [
{
"name": "I have 42 cukes in my belly"
},
{
"name": "I wait 1 hour"
},
{
"name": "my belly should growls"
}
]
},
{
"id": "belly;a-few-cukes-with-new-test",
"tags": [
{
"name": "#tag2"
}
],
"steps": [
{
"name": "I have 42 cukes in my belly"
},
{
"name": "I wait 1 hour"
},
{
"name": "my belly should growl"
}
]
}
]
},
{
"id": "newbelly",
"scenarios": [
{
"id": "newbelly;a-few-cukes-with-new-feature",
"tags": [
{
"name": "#tag1"
}
],
"steps": [
{
"name": "I have 42 cukes in my belly"
},
{
"name": "I wait 1 hour"
},
{
"name": "my belly should growls"
}
]
}
]
}
]
}
I would like to retrieve all the unique tag names: i.e., #tag1, #tag2. If you notice, the #tag1 is repeated twice.
My template:
{{#getTags features}}
{{#scenarios}}
{{#tags}}
<p>{{name}}</p>
{{/tags}}
{{/scenarios}}
{{/getTags}}
Custom Helper that I created so far:
Handlebars.registerHelper('getTags', function(context, block) {
var ret = "";
for (var i = 0; i < context.length; i++) {
ret += block.fn(context[i]);
};
return ret;
});
The above custom helper returns all the tags, but I want unique ones.
Something along these lines may work:
Handlebars.registerHelper('getTags', function(context, block) {
var ret = "";
var got = [];
function contains(obj, a) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
for (var i = 0; i < context.length; i++) {
if (!this.contains(context[i],got)) {
got.addObject(context[i]);
ret += block.fn(context[i]);
}
}
return ret;
});
Code used for testing, all javascript:
var ret = "";
var got = [];
var data = ["tag1", "tag1", "tag2", "tag3"]
function contains(obj, a) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
for (var i = 0; i < data.length; i++) {
if (!contains(data[i],got)) {
got.push(data[i]);
ret += data[i];
}
}
console.log( ret);

Categories