Onclick doesn't work inside anchor element - javascript

I have problem with anchor element and onclick attribute. The idea is that I have main function loadTableWithFilters that gets values from the pet data base and then draws a table with pets. The other functions are intended to change filters and call loadTableWithFilters function again. The problem that I have is with function calls from my html file.
This simply doesn't work
<li><a onclick="filterAllPets()">All Pets</a></li>
It gives me this error
Uncaught ReferenceError: filterAllPets is not defined
at HTMLAnchorElement.onclick
What I tried to do to solve this problem:
moved my <script> tags before </body>
changed function loadTableWithFilters ( petData ) to var loadTableWithFilters = function ( petData )
I know that I can give id to anchors and write some snippets like #id.onclick = function() but that's not the intention. I really don't understand why it doesn't work. Please explain it.
Code files
main.html
<!doctype html>
<html>
<head>
<title>~ Purfect Pets ~</title>
<link rel="stylesheet" href="css/normalize.css" />
<link rel="stylesheet" href="css/assignment4-theme.css" />
<link rel="stylesheet" href="css/a4-main.css" />
<!-- development css -->
<style>
table, td, th {
border: 1px solid black;
}
</style>
</head>
<body>
<header>
<div class="center">
<h1 class="app-title">
~ Purfect Pets ~
</h1>
</div>
</header>
<nav>
<div class="center">
<ul>
<li><a onclick="filterAllPets()">All Pets</a></li>
<li><span>|</span></li>
<li><a onclick="filterDog()">Dogs</a></li>
<li><a onclick="filterCat()">Cats</a></li>
<li><a onclick="filterBird()">Birds</a></li>
<li><span>|</span></li>
<li><a onclick="filter_zero_1()">< 1 year</a></li>
<li><a onclick="filter_1_3()">1 - 3 years</a></li>
<li><a onclick="filter_4_plus()">4+ years</a></li>
</ul>
</div>
</nav>
<section class="main center">
<table class="main-table-top">
<tbody>
<tr>
<th>Photo</th>
<th>Description</th>
</tr>
</tbody>
</table>
<div class="main-table-container">
<table class="main-table">
<tbody id="main-table-body">
<!-- tester -->
</tbody>
</table>
</div>
</section>
<footer>
<div class="center">
© 2017 Anton Elistratov
</div>
</footer>
<script src="js/data.js"></script>
<script src="js/a4-main.js"></script>
</body>
</html>
a4-main.js
//a4-main.js
window.onload = function() {
var filterType = ""; // sets the filter type to "" (will later be dog, cat or bird)
var filterAgeMin = 0; // sets the filter age min to 0 (for no minimum age filter)
var filterAgeMax = Number.MAX_VALUE; // sets the filter age max to the largest number possible (for no maximum age filter)
//
var loadTableWithFilters = function ( petData ){
var htmlRow = document.querySelector('#main-table-body');//getting my placeholder
htmlRow.innerHTML = "";//clearing
var i;//for loop increment
for (i = 0; i < petData.length; i++){
//$('#main-table-body tr td').append('<img src="' + petData[i].image.src + '"/>');
//getting image
if (petData[i].type === filterType || filterType === "" && petData[i].age >= filterAgeMin && petData[i].age <= filterAgeMax){
var image = document.createElement('img');
image.src = petData[i].image.src;
image.alt = petData[i].image.alt;
image.height = petData[i].image.height;
image.width = petData[i].image.width;
//getting name
var name = document.createElement('h4');
name.textContent = petData[i].name;
//getting description
var description = document.createElement('p');
description.innerHTML = petData[i].description;
//getting age
var age = document.createElement('span');
age.textContent = petData[i].age;
var type = petData[i].type;
//append('<li><img src="' + imgSrc[i] + '"/></li>');
var fullRow = document.createElement('tr');
var colLeft = document.createElement('td');
var colRight = document.createElement('td');
colLeft.appendChild(image);
colRight.appendChild(name);
colRight.appendChild(description);
colRight.appendChild(age);
//table assembly
fullRow.appendChild(colLeft);
fullRow.append(colRight);
htmlRow.appendChild(fullRow);
}
}//for (i = 0; i < petData.length; i++)
}
/* My filters */
//filters dogs
var filterDog = function () {
filterType = "dog";
loadTableWithFilters( petData );
}
//filters cats
var filterCat = function () {
filterType = "cat";
loadTableWithFilters( petData );
}
var filterBird = function () {
filterType = "bird";
loadTableWithFilters( petData );
}
//must be invoked when the user clicks "< 1 year"
var filter_zero_1 = function (){
filterAgeMin = 0;
filterAgeMax = 1;
loadTableWithFilters( petData );
}
//must be invoked when the user clicks "1 - 3 years"
var filter_1_3 = function (){
filterAgeMin = 1;
filterAgeMax = 3;
loadTableWithFilters( petData );
}
//must be invoked when the user clicks "4+ years"
var filter_4_plus = function () {
filterAgeMin = 4;
filterAgeMax = Number.MAX_VALUE;
loadTableWithFilters( petData );
}
/*This function simply sets the global filterType variable to "", the filterAgeMin variable to 0, the filterAgeMax variable to Number.MAX_VALUE and invokes the loadTableWithFilters function again to refresh the table. This function must be invoked when the user clicks "All Pets"*/
var filterAllPets = function () {
filterType = "";
filterAgeMin = 0;
filterAgeMax = Number.MAX_VALUE;
loadTableWithFilters( petData );
}
//function call
loadTableWithFilters( petData );
};//window.onload = function()
data.js
//data.js
var petData = [
{
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Bella.jpg", alt: "Bella", width: 120, height: 160 },
name: "Bella",
age: 0.5,
description: "<span>Bella</span> is a bright young pup who loves being around other dogs and doesn't mind the odd cat.<br />Her <span>favourite treat</span> is <span>bacon</span> - anything <span>bacon</span>.",
type: "dog"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Buddy.jpg", alt: "Buddy", width: 120, height: 160 },
name: "Buddy",
age: 4,
description: "One of the most friendly dogs currently staying with us is <span>Buddy</span>.<br />He's a little older but has a <span>lot of love</span> to give.<br />His favourite activity is cuddling up and <span>watching a movie</span> with is owner.",
type: "dog"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Charlie.jpg", alt: "Charlie", width: 120, height: 160 },
name: "Charlie",
age: 3,
description: "<span>Charlie</span> loves <span>spending time outdoors</span>. <br />He will chase anything that moves and will spend all day <span>playing fetch</span> in the park. <br />His favourite treat to eat is actually <span>broccoli</span> - crazy I know, but he loves it.",
type: "dog"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Jasper.jpg", alt: "Jasper", width: 120, height: 160 },
name: "Jasper",
age: 2,
description: "<span>Jasper</span> is only 2 years (and 3 months) old, but he's already one of the smartest pups we've seen.<br /> He will recognize his <span>toys by name</span> and will always put them back in the toy box when asked.<br />He's the only dog we've seen that <span>tidies up after himself!</span>.",
type: "dog"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Max.jpg", alt: "Max", width: 120, height: 160 },
name: "Max",
age: 5,
description: "Our little <span>Max</span> is always happy.<br />He loves to spend his time outdoors <span>playing fetch</span> and <span>going for jogs</span>.<br /> His favourite treats are <span>hot dogs</span> - any variety will do, but he loves Schneiders <span>Red Hots</span> the best.",
type: "dog"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/David.jpg", alt: "David", width: 120, height: 160 },
name: "David",
age: 0.5,
description: "<span>David</span> is our smallest kitten at only <span>6 months old</span>! <br />His favourite thing right now is <span>chasing his tail</span> and playing with <span>packing peanuts</span>.<br />He is full of love and will make a welcome addition to any home.",
type: "cat"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Simba.jpg", alt: "Simba", width: 120, height: 160 },
name: "Simba",
age: 5,
description: "One of our oldest cats is <span>Simba</span>.<br /> He's over chasing things and is just looking for a nice place to <span>cuddle</span> - usually somebody's lap.<br /> He loves <span>Temptations</span> (any variety) and will <span>come running</span> from anywhere in the house if he suspects treats are on the way.",
type: "cat"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Sparky.jpg", alt: "Sparky", width: 120, height: 160 },
name: "Sparky",
age: 2,
description: "<span>Sparky</span> is a very wild cat, but he's a <span>ton of fun</span>.<br />He would happily spend his days chasing <span>bugs</span> or <span>squirrels</span> outside or <span>playing with you</span> inside!<br /> His favourite treat is <span>cottage cheese</span> and will eat it straight from the container if you let him.",
type: "cat"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Whiffles.jpg", alt: "Whiffles", width: 120, height: 160 },
name: "Whiffles",
age: 3,
description: "<span>Whiffles</span> is our first <span>hypoallergenic</span> cat.<br />She is very mellow and extremely friendly, making her the perfect indoor cat.<br />Her favourite treat is <span>Tuna</span> straight from the can - any variety.",
type: "cat"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Widget.jpg", alt: "Widget", width: 120, height: 160 },
name: "Widget",
age: 1.5,
description: "One of our <span>youngest</span> cats is <span>Widget</span>. <br /> He's only 18 months old and still loves to run and jump and <span>chase his toys</span>.<br />His favourite food is <span>Salmon</span>, but he will always come running for any variety of <span>cat treats</span> (i.e. Temptations, Greenies, etc). ",
type: "cat"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Augustus.jpg", alt: "Augustus", width: 120, height: 160 },
name: "Augustus",
age: 1.5,
description: "<span>Augustus</span> has been with us for just over <span>4 months</span>, and already we can see that he's <span>very friendly</span>.<br /> He will <span>chirp</span> and <span>chatter</span> whenever somebody enters the room. ",
type: "bird"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Joanna.jpg", alt: "Joanna", width: 120, height: 160 },
name: "Joanna",
age: 0.5,
description: "One of our youngest birds is <span>Joanna</span>. She is only 6 months old, but is very active.<br /> She loves <span>flying outside</span> of her cage, but will never go far. Like all birds her age, she loves playing with the “<span>bird in the mirror</span>”.",
type: "bird"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Jonathan.jpg", alt: "Jonathan", width: 120, height: 160 },
name: "Jonathan",
age: 3,
description: "<span>Jonathan</span> is one of our older birds, but is still very friendly and loves to <span>chirp and sing</span> in the morning.<br /> He loves taking <span>baths</span>, so as long as there's a <span>water bowl</span> in his cage, he'll be happy all day.",
type: "bird"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Sammy.jpg", alt: "Sammy", width: 120, height: 160 },
name: "Sammy",
age: 2.5,
description: "<span>Sammy</span> is one of our older birds, but he's also the <span>smartest</span>. He is always trying to <span>mimic</span> whatever sounds are around him. He is also a very active bird, so be sure you are able to interact with him <span>multiple</span> times a day.<br />His favourite thing is when you <span>scratch</span> under his chin. ",
type: "bird"
}, {
image: { src: "https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2017/web222/assignment4/pets/Suzette.jpg", alt: "Suzette", width: 120, height: 160 },
name: "Suzette",
age: 4,
description: "The oldest bird currently staying with us is <span>Suzette</span>. She's extremely <span>cuddly</span> and loves landing on people's glasses, collars, hats, or whatever she can get her little claws on, as long as she can be close. She's a great <span>companion</span> for anyone looking for a bird that will interact with them and remain <span>close by</span>.",
type: "bird"
}
];

Just remove it from window.load and it will work.
From this:
window.onload = function() {
var filterType = ""; // sets the filter type to "" (will later be dog, cat or bird)
var filterAgeMin = 0; // sets the filter age min to 0 (for no minimum age filter)
var filterAgeMax = Number.MAX_VALUE; // sets the filter age max to the largest number possible (for no maximum age filter)
//
var loadTableWithFilters = function(petData) {
var htmlRow = document.querySelector('#main-table-body'); //getting my placeholder
htmlRow.innerHTML = ""; //clearing
var i; //for loop increment
for (i = 0; i < petData.length; i++) {
//$('#main-table-body tr td').append('<img src="' + petData[i].image.src + '"/>');
//getting image
if (petData[i].type === filterType || filterType === "" && petData[i].age >= filterAgeMin && petData[i].age <= filterAgeMax) {
var image = document.createElement('img');
image.src = petData[i].image.src;
image.alt = petData[i].image.alt;
image.height = petData[i].image.height;
image.width = petData[i].image.width;
//getting name
var name = document.createElement('h4');
name.textContent = petData[i].name;
//getting description
var description = document.createElement('p');
description.innerHTML = petData[i].description;
//getting age
var age = document.createElement('span');
age.textContent = petData[i].age;
var type = petData[i].type;
//append('<li><img src="' + imgSrc[i] + '"/></li>');
var fullRow = document.createElement('tr');
var colLeft = document.createElement('td');
var colRight = document.createElement('td');
colLeft.appendChild(image);
colRight.appendChild(name);
colRight.appendChild(description);
colRight.appendChild(age);
//table assembly
fullRow.appendChild(colLeft);
fullRow.append(colRight);
htmlRow.appendChild(fullRow);
}
} //for (i = 0; i < petData.length; i++)
}
/* My filters */
//filters dogs
var filterDog = function() {
filterType = "dog";
loadTableWithFilters(petData);
}
//filters cats
var filterCat = function() {
filterType = "cat";
loadTableWithFilters(petData);
}
var filterBird = function() {
filterType = "bird";
loadTableWithFilters(petData);
}
//must be invoked when the user clicks "< 1 year"
var filter_zero_1 = function() {
filterAgeMin = 0;
filterAgeMax = 1;
loadTableWithFilters(petData);
}
//must be invoked when the user clicks "1 - 3 years"
var filter_1_3 = function() {
filterAgeMin = 1;
filterAgeMax = 3;
loadTableWithFilters(petData);
}
//must be invoked when the user clicks "4+ years"
var filter_4_plus = function() {
filterAgeMin = 4;
filterAgeMax = Number.MAX_VALUE;
loadTableWithFilters(petData);
}
/*This function simply sets the global filterType variable to "", the filterAgeMin variable to 0, the filterAgeMax variable to Number.MAX_VALUE and invokes the loadTableWithFilters function again to refresh the table. This function must be invoked when the user clicks "All Pets"*/
var filterAllPets = function() {
filterType = "";
filterAgeMin = 0;
filterAgeMax = Number.MAX_VALUE;
loadTableWithFilters(petData);
}
//function call
loadTableWithFilters(petData);
}; //window.onload = function()
to this:
var filterType = ""; // sets the filter type to "" (will later be dog, cat or bird)
var filterAgeMin = 0; // sets the filter age min to 0 (for no minimum age filter)
var filterAgeMax = Number.MAX_VALUE; // sets the filter age max to the largest number possible (for no maximum age filter)
//
var loadTableWithFilters = function(petData) {
var htmlRow = document.querySelector('#main-table-body'); //getting my placeholder
htmlRow.innerHTML = ""; //clearing
var i; //for loop increment
for (i = 0; i < petData.length; i++) {
//$('#main-table-body tr td').append('<img src="' + petData[i].image.src + '"/>');
//getting image
if (petData[i].type === filterType || filterType === "" && petData[i].age >= filterAgeMin && petData[i].age <= filterAgeMax) {
var image = document.createElement('img');
image.src = petData[i].image.src;
image.alt = petData[i].image.alt;
image.height = petData[i].image.height;
image.width = petData[i].image.width;
//getting name
var name = document.createElement('h4');
name.textContent = petData[i].name;
//getting description
var description = document.createElement('p');
description.innerHTML = petData[i].description;
//getting age
var age = document.createElement('span');
age.textContent = petData[i].age;
var type = petData[i].type;
//append('<li><img src="' + imgSrc[i] + '"/></li>');
var fullRow = document.createElement('tr');
var colLeft = document.createElement('td');
var colRight = document.createElement('td');
colLeft.appendChild(image);
colRight.appendChild(name);
colRight.appendChild(description);
colRight.appendChild(age);
//table assembly
fullRow.appendChild(colLeft);
fullRow.append(colRight);
htmlRow.appendChild(fullRow);
}
} //for (i = 0; i < petData.length; i++)
}
/* My filters */
//filters dogs
var filterDog = function() {
filterType = "dog";
loadTableWithFilters(petData);
}
//filters cats
var filterCat = function() {
filterType = "cat";
loadTableWithFilters(petData);
}
var filterBird = function() {
filterType = "bird";
loadTableWithFilters(petData);
}
//must be invoked when the user clicks "< 1 year"
var filter_zero_1 = function() {
filterAgeMin = 0;
filterAgeMax = 1;
loadTableWithFilters(petData);
}
//must be invoked when the user clicks "1 - 3 years"
var filter_1_3 = function() {
filterAgeMin = 1;
filterAgeMax = 3;
loadTableWithFilters(petData);
}
//must be invoked when the user clicks "4+ years"
var filter_4_plus = function() {
filterAgeMin = 4;
filterAgeMax = Number.MAX_VALUE;
loadTableWithFilters(petData);
}
/*This function simply sets the global filterType variable to "", the filterAgeMin variable to 0, the filterAgeMax variable to Number.MAX_VALUE and invokes the loadTableWithFilters function again to refresh the table. This function must be invoked when the user clicks "All Pets"*/
var filterAllPets = function() {
filterType = "";
filterAgeMin = 0;
filterAgeMax = Number.MAX_VALUE;
loadTableWithFilters(petData);
}
//function call
loadTableWithFilters(petData);

Related

How to implement multiple tag search across my image gallery with JavaScript?

I have an image gallery with search input , where the user can type image title or image tag and search for matches. I now need to be able to have multiple search for the tags. For example if i type : #tree - > the result will be all the images that have "tree" in their tags (specifically ) , not the ones that partially contains the word, as Tag search should be specific. I need to be able to type : #tree,#sky - > and the output to be all the images that have "tree" and "sky" in them . So far my code executes only the first example .
HTML :
<div class="searchBtn">
<input type="text" id="inputValue" placeholder="Search by name or #tag">
<button onclick="Search()" type="button">Search</button>
</div>
JS:
let filterSearch = $("#inputValue").val().toLowerCase();
function findAllImages(filter, start, itemsCount) {
let photos = [];
let tagSign = "#";
const searchByTag = filterSearch [0] === tagSign;
let searchCondition = searchByTag ? filterSearch.slice(1) : filter;
let newFiltered = imageArrayPhotos.filter(
searchByTag ? image => image.tag.indexOf(searchCondition) >= 0 :
image => image.title.toLowerCase().indexOf(searchCondition) >= 0);
for (let i = start; i < newFiltered.length; i++) {
photos .push(newFiltered [i]);
if (photos.length >= numberOfImages) {
break;
}
}
return photos ;
}
Can i do it with a callback function on let newFiltered = imageArrayPhotos.filter(function() {}) that goes through all the possibilities?
Why don't you use the regex. check if this is feasible.
let searchByTag = true;
let imageArrayPhotos = [{
tag: 'tree',
title: 'tree'
},
{
tag: 'forest',
title: 'tree'
},
{
tag: 'sky',
title: 'sky'
},
{
tag: 'bird',
title: 'bird'
},
{
tag: 'watertree',
title: 'sky'
},
];
let filterSearch = '';
let searchCondition = '';
let pattern;
let newFiltered = [];
function Search() {
newFiltered = [];
filterSearch = '';
searchCondition = '';
filterSearch = $("#inputValue").val();
filterSearch = filterSearch.split(',');
//searchCondition = searchByTag ? filterSearch.slice(1) : filter;
//newFiltered = imageArrayPhotos.filter(checkFilter);
filterSearch.forEach(function(item) {
item = $.trim(item);
searchByTag = item[0] == "#";
pattern = new RegExp("^" + $.trim(item).replace(/#/g, '') + "$");
let itemData = imageArrayPhotos.filter(checkFilter);
if (itemData.length > 0) {
newFiltered = newFiltered.concat(itemData);
}
});
console.log(newFiltered);
}
function checkFilter(image) {
return searchByTag ? pattern.test(image.tag) :
pattern.test(image.title)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="searchBtn">
<input type="text" id="inputValue" placeholder="Search by name or #tag">
<button onclick="Search()" type="button">Search</button>
</div>

for loop to append 3 different values in JavaScript

How can I give the output as: Name:..., Description:..., Main Temp:... Instead of: Name:..., Name:..., Name:..., Description..., Description:..
for (var i = 0; i < 3; i++) {
$('#name').append('<b>Name:</b><ul>' + `<li>${name[i]}</li>` + '</ul>');
$('#main_temp').append('<b>Main Temp: </b><ul>' + `<li>${mainTemp[i]}</li>` + '</ul>');
$('#weather_description').append('<b>Weather Description:</b><ul>' + `<li>${description[i]}</li>` + '</ul>');
}
output:
Name:
Vancouver
Name:
Vancouver
Name:
Vancouver
Weather Description:
light rain
Weather Description:
light rain
Weather Description:
clear sky
Main Temp:
289.917
Main Temp:
286.551
Main Temp:
285.244
You might be looking for something like this:
JS
var text = '';
for (var i = 0; i < 3; i++) {
text= '';
text = '<ul>' +
`<li><b>Name: </b>${name[i]}</li>` +
`<li><b>Main Temp: </b>${mainTemp[i]}</li>` +
`<li><b>Weather Description: </b>${description[i]}</li>` +
'</ul>';
$('#container').append(text);
}
HTML
<div id="container">
</div>
The problem is that you are appending always to the same element.
You could use a template to extract the html from your logic and to better define the groupings by which your output should exist in.
var names = [ 'Vancouver', 'Vancouver', 'Vancouver' ];
var description = [ 'light rain', 'light rain', 'light rain' ];
var mainTemp = [ 289.917, 286.551, 285.244 ];
var template = document.querySelector('#outputTemplate').innerHTML;
var $output = $('#output');
for (var i = 0; i < 3; i++) {
let $template = $(template);
$template.find('.name').text(names[i]);
$template.find('.description').text(description[i]);
$template.find('.mainTemp').text(mainTemp[i]);
$output.append($template);
}
.group {
border: 1px solid rgb(0, 0, 0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output">
</div>
<script type="text/html" id="outputTemplate">
<div class="group">
<label>
<b>Name:</b><ul><li class="name"></li></ul>
</label>
<label>
<b>Weather Description:</b><ul><li class="description"></li></ul>
</label>
<label>
<b>Main Temp:</b><ul><li class="mainTemp"></li></ul>
</label>
</div>
</script>

Scrolling/Sorting/Searching/Swapping two really long lists

Suppose I have two really long lists of People, ~20,000 each, but only one list is displayed at a given time. Each Person has a Name, Nickname, and Age. The goal is to display each and every person in a list that can be scrolled, sorted, and searched efficiently. In addition, I need to be able to swap between lists. I have been able to create the desired functionality, but the individual operations are not very user friendly. The scrolling is not smooth and sorting/searching/swapping can freeze the UI for a second or two, and sometimes the page will even crash. Therefore I am looking for improvements on the following code, and am wondering if a smooth user experience is even possible with lists of this size without having to use virtual rendering (only populating the DOM with what is visible by the viewport and faking the scroll bar). Thanks in advance!
The Javascript is structured as:
var groupOne =
[
{name: "Michael", nickname: "Mike", age: 23},
{name: "Matthew", nickname: "Matt", age: 25},
{name: "Aaron", nickname: "Ron", age: 30},
...
]
var groupTwo =
[
{name: "Joseph", nickname: "Joe", age: 20},
{name: "Carter", nickname: "C", age: 30},
{name: "William", nickname: "Will", age: 40},
...
]
A Person is displayed as:
---------------------------------
| Name | |
-------------------------| Age |
| Nickname | |
---------------------------------
The HTML is structured as:
<input id="search" type="text">
<button id="sort"></button>
<button id="swap"></button>
<ol id="people">
<li class="person" data-name="Michael" data-nickname="Mike" data-age="23">
<p class="name">Michael</p>
<p class="nickname">Mike</p>
<p class="age">23</p>
</li>
<li class="person" data-name="Matthew" data-nickname="Matt" data-age="25">
<p class="name">Matthew</p>
<p class="nickname">Matt</p>
<p class="age">25</p>
</li>
<li class="person" data-name="Aaron" data-nickname="Ron" data-age="30">
<p class="name">Aaron</p>
<p class="nickname">Ron</p>
<p class="age">30</p>
</li>
...
</ol>
The code for searching is:
$("#search").change(function ()
{
var search = $(this).val();
var list = document.getElementById("people");
var items = list.children;
for (var i = 0; i < items.length; i++)
{
var item = items[i];
var name = item.getAttribute("data-name");
if(search == "")
{
item.style.display = "block";
}
else if(name.indexOf(search) != -1)
{
item.style.display = "block";
}
else
{
item.style.display = "none";
}
}
});
The code for sorting is:
$("#sort").click(function ()
{
var list = document.getElementById("people");
var items = list.children;
var itemArray = [];
for (var i = 0; i < items.length; i++)
{
itemArray.push(items[i]);
}
itemArray.sort(function (a, b)
{
var nameA = a.getAttribute("data-name");
var nameB = b.getAttribute("data-name");
return nameA.localeCompare(nameB);
});
for (var i = 0; i < itemArray.length; i++)
{
list.appendChild(itemArray[i]);
}
});
The code for swapping is:
$("#swap").click(function ()
{
var $people = $("#people");
$people.empty();
for(var i = 0; i < groupTwo.length; i++)
{
var person = groupTwo[i];
var container = document.createElement("li");
container.className = "person";
container.setAttribute("data-name", person.name);
container.setAttribute("data-nickname", person.nickname);
container.setAttribute("data-age", person.age);
var nameParagraph = document.createElement("p");
nameParagraph.className = "name";
nameParagraph.textContent = person.name;
var nicknameParagraph = document.createElement("p");
nicknameParagraph.className = "nickname";
nicknameParagraph.textContent = person.nickname;
var ageParagraph = document.createElement("p");
ageParagraph.className = "age";
ageParagraph.textContent = person.age;
container.appendChild(nameParagraph);
container.appendChild(nicknameParagraph);
container.appendChild(ageParagraph);
$people.append(container);
}
});
Discoveries so far:
Absolute Positioning really hurts smoothness of scrolling
Using nested divs for positioning really improves scrolling but hurts swapping via $.empty(), sorting via $.append(), and even causes crashes
Inline Block seems to be better for scrolling than float
Table Layout may improve scrolling but doesn't help with swapping/sorting

Unable to retrieve data objects from my JSON file

I've created a JSON file to call out the name of a list of beers to display ABV and country but I am unable to display the results on the webpage. I was able to get the select tag to drop down the list, but when selecting a beer, it will only show the selected results as "undefined."
Here is the JS code I have so far...
var $select = $("#beerListing");
var beer = Array();
var country = Array();
$.getJSON("data.json", function(data) {
$select.html('');
for (var i = 0; i < data['beer'].length; i++)
$select.append('<option id="' + data["beer"][i]['id'] + '">' + data["beer"][i]["beer_name"] + '</option>');
for (x in data) {
if (beer.indexOf(data[x].beer_name) < 0) {
var y = beer.length;
beer[y] = data[x].beer_name;
country[y] = data[x].brewery_country;
}
}
showBeerList();
});
function showBeerList() {
var select = document.getElementById('beerListing');
for (var i = 0; i < beer.length; i++) {
var obj = document.createElement("option");
obj.text = beer[i];
obj.value = i;
select.appendChild(obj);
}
}
function getBeerInfo(picked) {
if (picked == "Pick Your Poison...") {
location.reload();
} else {
document.getElementById("name").innerHTML = beer[picked];
document.getElementById("country").innerHTML = country[picked];
}
}
HTML:
<html>
<head></head>
<body>
<h1>LCBO API TESTING</h1>
<select name="beerlist" id="beerListing" class="form-control" onchange="getBeerInfo(this.value)">
</select>
<br>
<label>Name:</label>
<label id="name">--</label>
<br>
<label>Country:</label>
<label id="country">--</label>
<br>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="main.js"></script>
</body>
</html>
JSON List called data.json
{
"beer": [{
"beer_name": "Organic Devon Cider",
"brewery_name": "Luscombe Organic Drinks",
"beer_type": "Cider",
"beer_abv": "4.9",
"beer_ibu": "0",
"comment": "",
"venue_name": "The Anchor & Hope",
"venue_city": "London",
"venue_state": "Greater London",
"brewery_country": "England"
}, {
"beer_name": "Beer A",
"brewery_name": "Beer A",
"beer_type": "Cider",
"beer_abv": "4.9",
"beer_ibu": "0",
"comment": "",
"venue_name": "Beer",
"venue_city": "New York",
"venue_state": "New York",
"brewery_country": "USA"
}]
}
You seemed to be adding the options to the select element twice and using for-in which iterates properties, not entries in an array.
Below snippet will not work as requires external data source.
var $select = $("#beerListing") ;
var beer = Array();
var country = Array();
$.getJSON("data.json", function(data) {
$select.html('');
for (var i = 0; i < data.beer.length; i = i + 1) {
if (beer.indexOf(data.beer[i].beer_name) < 0) {
beer.push(data.beer[i].beer_name);
country.push(data.beer[i].brewery_country);
}
}
showBeerList();
}
function showBeerList() {
var select = document.getElementById('beerListing');
for (var i = 0; i < beer.length; i++) {
var obj = document.createElement("option");
obj.text = beer[i];
obj.value = i;
select.appendChild(obj);
}
}
function getBeerInfo(picked) {
if (picked == "Pick Your Poison...") {
location.reload();
}
else {
document.getElementById("name").innerHTML = beer[picked];
document.getElementById("country").innerHTML = country[picked];
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>LCBO API TESTING</h1>
<select name="beerlist" id="beerListing" class="form-control" onchange="getBeerInfo(this.value)">
</select>
<br>
<label>Name:</label>
<label id="name">--</label>
<br>
<label>Country:</label>
<label id="country">--</label>
<br>
I got it working here: https://jsfiddle.net/bu7pkb5f/1/
What are you doing with:
if (beer.indexOf(data[x].beer_name) < 0) {
var y = beer.length;
beer[y] = data[x].beer_name;
country[y] = data[x].brewery_country;
}
I don't understand it but it's creating a third item in the list after the two real beer entries are processed. I left it commented out in the fiddle so you can check it out for yourself.

Send a random number from one function to be used by another.

I am working on a word game with javascript.
I need to pass a random number created by an onclick event in one function to another. The other function fires with a onclick event.
(I allready tried to send the random number as a parameter to the new
funcion and it worked, but not with the clickevent)
The first method, spelet.word, picks a random eng word fron an array of 10 words.
The second method, spelet.answer, checks if it is correctly spelled. It does so by taking the same randomly generated number from first method to pick the right word for the array of words.
Problem is I cant acess the randomly created number from the first method with onclick.
The relevant HTML
<form>
<input type="text" value="eng" id="eng" />
<!-- the english word-->
<input type="text" value="sve" id="sve" />
<!-- the swedish word-->
<input type="button" value="Nytt Ord" onclick='spelet.word();' />
<br />
<!-- Generates a random english word from an array of 10 words-->
<input type="button" value="Svara" onclick='spelet.answer();' />
<br />
<!-- The user use this button to submit the swedish word-->
</form>
var $Lars = {};
var objwords = //Måste ha som global för att alla metoder ska nå den.
{
ord: [{
eng: "bird",
sve: "fågel"
}, {
eng: "car",
sve: "bil"
}, {
eng: "food",
sve: "mat"
}, {
eng: "coffee",
sve: "kaffe"
}, {
eng: "water",
sve: "vatten"
}, {
eng: "woman",
sve: "kvinna"
}, {
eng: "cup",
sve: "kopp"
}, {
eng: "pen",
sve: "penna"
}, {
eng: "beer",
sve: "öl"
}, {
eng: "desert",
sve: "öken"
}, {
eng: "stone",
sve: "sten"
}]
}
$Lars.Play = function()
{
var c;
this.word = function() {
//---------- doing a random number-----------------//
var c = Math.floor(Math.random() * 10) + 1;
//spelet.answer(c); DID NOT WORK
document.getElementById('eng').value = objwords.ord[c].eng;
var i = 0; //using the random number to pick up en english word
for (i = 0; i < objwords.ord.length; i++) {
document.getElementById('eng').value = objwords.ord[c].eng;
}
document.getElementById('nr').value = c;
//return c; DID NOT WORK
}
this.answer = function() //the same random number picks up the swedish word and
//check if it is correct spelled
{
var svaret = document.getElementById('sve').value;
var q = 0;
for (q = 0; q < objwords.ord.length; q++) {
if (objwords.ord[c].sve == svaret) {} //something happens when correct answer;}
else {} //something happens when incorrect answer;}
}
}
}
var spelet = new $Lars.Play();
You need a more globaly scoped variable for that. A minimal example:
function Play (){
this.c = -1;
}
Play.prototype.word = function(){
this.c = Math.floor(Math.random() * 10) + 1;
console.log("Produced: " + this.c);
}
Play.prototype.answer = function(){
console.log("Got " + this.c);
}
var playit = new Play();
playit.word();
playit.answer();
playit.word();
playit.answer();
You don't need to spell the protoypes out, I just thought it would make it more obvious.

Categories