Chrome - Hiding scrolled content causing body and other elements to scroll up - javascript

I am dividing my webpage in two vertical parts. Where left panel is used to render a list of categories of books and right panel is used for rendering books associated with selected category. We also have buttons to hide a specific category from left side.
<div class="content">
<div class='col-3'>
<h3> Category </h3>
<div class="category-container dev-category-list">
</div>
</div>
<div class='col-9'>
<h3> Books </h3>
<div class="books-container dev-books-list">
</div>
</div>
</div>
Javascript Code:
var categories = ['category-1','category-2','category-3','category-4','category-5','category-6','category-7'];
var books = {'cat1':['1984','Dracula','Twilight','Holes','Homes','Uglies','Othello'],'cat2':['Dracula','Twilight','1984','Holes','Homes','Uglies','Othello'],'cat3':['1984','Twilight','Holes','Homes','Dracula','Uglies','Othello'],'cat4':['Othello','1984','Dracula','Uglies','Holes','Twilight','Eclipse'],'cat5':['Hamlet','Macbeth','Othello','Holes','Night','Twilight','Eclipse'],'cat6':['1984','Hamlet','Dracula','Uglies','Othello','Night','Twilight'],'cat7':['1984','Hamlet','Macbeth','Uglies','Othello','Holes','Night']};
setup_UI_elements();
function setup_UI_elements(){
appendCategories();
renderBooks('1');
addCategListner();
addBtnListner();
}
function appendCategories(){
container = $('.dev-category-list');
for(var i=0; i< categories.length; i++){
categHtml = "<div data-categ-id='"+ (i+1) + "' class='categ'> "+categories[i]+" </div>";
container.append(categHtml)
}
}
function renderBooks(categ_id){
container = $('.dev-books-list');
container.html('');
categ_key = 'cat'+categ_id
$('.categ').removeClass('selected');
$('div.categ[data-categ-id='+categ_id+']').addClass('selected');
for(var i=0; i< books[categ_key].length; i++){
bookHTML = "<div data-book-id='"+ (i+1) + "' class='book'> "+books[categ_key][i];
bookHTML += "<button type='button' data-book-id='"+ (i+1) + "' data-categ-id='"+ (books[categ_key].length-i) + "' class='btn'> Hide Categ "+ (books[categ_key].length-i) +"</button> </div>";
container.append(bookHTML);
}
}
function addCategListner(){
container = $('.dev-category-list');
container.click(function(e){
target = $(e.target);
$('.categ').removeClass('selected hidden');
target.toggleClass('selected');
categ_id = target.data('categ-id');
renderBooks(categ_id);
});
}
function addBtnListner(){
container = $('.dev-books-list');
container.click(function(e){
target = $(e.target);
if(target.hasClass('btn')){
categ_id = target.data('categ-id');
target.toggleClass('added');
if(target.hasClass('added'))
target.html('Show Categ'+categ_id)
else
target.html('Hide Categ'+categ_id)
categDiv = $('.dev-category-list div[data-categ-id='+categ_id+']')
categDiv.toggleClass('hidden');
}
});
}
When I try to hide a category from left panel which is no longer in above the fold then it is scrolling right panel instead of left panel.
I works fine in Firefox and Safari.
JS Bin: https://jsbin.com/bafasoy/edit?html,js,output

Related

Javascript inserting html code without closing tags

I have a list of table columns. I would like to display them in one row.
What am I trying is :
for (var i = 0; i < key.length; i++) {
writeToScreen3('<div class="col-sm">' + key[i] + '</div>'); //column name
}
function writeToScreen3(message) {
var pre = document.createElement("p"); //I realize I am creating another element <p> How to do it diffrently?
pre.innerHTML = message;
output.appendChild(pre);
}
What I need is this transferred to JavaScript :
<div class="container">
<div class="row">
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
</div>
</div>
What I also tried :
function test8() {
$("#output").html('<div class="container">< div class= "row" >'); //but it always closes these 2 divs here . I want it not to close it. output is a div field
}
You can do something like this:
function createContainer(columns) {
function createDivWithClass(cls) {
const div = document.createElement('div');
div.classList.add(cls);
return div;
}
const container = createDivWithClass('container');
const row = createDivWithClass('row');
container.appendChild(row);
for (let i = 0; i < columns.length; i++) {
const column = createDivWithClass('col-sm');
column.textContent = columns[i];
row.appendChild(column);
}
return container;
}
const container = createContainer([1, 2, 3, 4]);
document.getElementById('output').appendChild(container);
console.log(container.outerHTML);
<div id="output"></div>
Here, I've defined a function called createDivWithClass to make it easier to create a <div> and set a class name to it.
Then, I'm using this function to create a <div class="container">, create a <div class="row"> and add that to the container, and then go through the columns array and create <div class="col-sm"> and add those to the row element.
Just like you can append elements to the #output element in the DOM, you can also append elements to elements that you've created and are not yet in the DOM.

Dynamically inserting html elements after the last instance of a class

I'm using newsapi to request JSON data, and am then dynamically loading it onto the page without reloading the page/going onto another page.
When the user initially goes onto the site, a request made on the backend will automatically be made and load the results onto the site via an EJS template. There will also be a button at the bottom of the page, so when a user clicks on it, new articles will be loaded.
The issue is that when the user clicks on the button, the new articles aren't appended after the last instance of a card-container. For example, say I have articles 1 2 3 4 5 already on the page and want to load articles 6 7 8 9, after clicking the button the articles are now in the order of 1 6 2 7 3 8 4 9 5. Where I want it to be in the order 1 2 3 4 5 6 7 8 9.
I've thought by using Jquerys insertAfter() function to insert each new element after the last would work, but it clearly doesn't.
Whilst the code I have below may be messy, I want to fix the logic before tidying it up.
JS
let more = document.getElementById("test");
more.addEventListener("click", function () {
(async () => {
const data = await fetch('http://localhost:3000/articles/');
const articles = await data.json()
for (let i = 0; i < articles.articles.length; i++) {
let newDate = articles.articles[i].date;
newDate = newDate.substring(0, newDate.indexOf('T')).split("-");
var articleList = document.getElementsByClassName("card-container");
var lastArticle = articleList[articleList.length - 1];
let cardContainer = document.createElement('div');
cardContainer.className += "card-container";
let card = document.createElement('div');
card.className += "card";
let content = document.createElement('div');
content.className += "content";
let thumbnail = document.createElement('div');
thumbnail.className += "thumbnail";
let image = document.createElement('img');
image.className += "image";
let text = document.createElement('div');
text.className += "text";
let title = document.createElement('div');
title.className += "title";
let a = document.createElement('a');
let meta = document.createElement('div');
meta.className += "meta";
let source = document.createElement('div');
source.className += "source";
let date = document.createElement('div');
date.className += "date";
document.getElementsByClassName('card-container')[i]
.appendChild(card).appendChild(content).appendChild(thumbnail)
.appendChild(image)
document.getElementsByClassName("content")[i]
.appendChild(text).appendChild(title).appendChild(a)
document.getElementsByClassName("text")[i]
.appendChild(meta).appendChild(source)
document.getElementsByClassName("meta")[i]
.appendChild(date)
let container = document.getElementById('article-container')
container.innerHTML = container.innerHTML + cardContainer;
image.setAttribute("src", articles.articles[i].image)
a.setAttribute('href', articles.articles[i].link);
a.innerHTML = articles.articles[i].title;
source.innerHTML = articles.articles[i].source.name;
date.innerHTML = newDate[1] + " " + newDate[2] + " " + newDate[0];
}
})();
})
Desired markup
<div class="card-container">
<div class="card">
<!-- Post-->
<div class="content">
<!-- Thumbnail-->
<div class="thumbnail">
<img
src="https://ssio.azurewebsites.net/x500,q75,jpeg/http://supersport-img.azureedge.net/2019/8/Man-City-190804-Celebrating-G-1050.jpg" />
</div>
<!-- Post Content-->
<div class="text">
<div class="title"><a
href="https://www.goal.com/en-gb/lists/deadline-day-dybala-coutinho-premier-league-transfers-happen/68rpu0erk0e81pm2anfv2ku16">Coutinho
llega a un acuerdo con el Arsenal para marcharse del Barcelona - PASIÓN
FUTBOL</a>
</div>
<div class="meta">
<div>Source</div>
<div class="date-text">07 07 2019</div>
</div>
</div>
</div>
</div>
</div>
JS Fiddle
I seem to have got it working - but not all of the JSON (other than the image) are being mapped to their divs inner HTML :/
https://jsfiddle.net/georgegilliland/ofxtsz2a/5/
In order to append in pure JS you have to take the last content of the container, append new data to it, then replace the container content with the new data.
I wrote a jsfiddle based on the stack overflow question I posted in the comment : https://jsfiddle.net/HolyNoodle/bnqs83hr/1/
var container = document.getElementById('container')
for(var i = 0; i < 3; i++) {
container.innerHTML = container.innerHTML + "<p>" + i + "</p>"
}
Here you can see I am getting the container inner html, appending new value to it, then replacing the container inner html by the new html
Fixed the issue... The problem was that I was getting elements by class name at whatever index the for loop was on. So if the for loop was on it's 5th iteration, it was appending content to the 5th instance of content, rather than appending it to the end of the container.
document.getElementById('article-container')
.appendChild(cardContainer)
.appendChild(card).appendChild(content).appendChild(thumbnail)
.appendChild(image)
document.getElementsByClassName("content")[i]
.appendChild(text).appendChild(title).appendChild(a)
document.getElementsByClassName("text")[i]
.appendChild(meta).appendChild(source)
document.getElementsByClassName("meta")[i]
.appendChild(date)
What I did to fix this was get the number of elements with the classname card-container before the for loop:
let nodelist = document.getElementsByClassName("card-container").length;
And then get elements at the index of the for loop summed with the amount nodelist.
document.getElementById('article-container')
.appendChild(cardContainer)
.appendChild(card).appendChild(content).appendChild(thumbnail)
.appendChild(image)
document.getElementsByClassName("content")[i + nodelist]
.appendChild(text).appendChild(title).appendChild(a)
document.getElementsByClassName("text")[i + nodelist]
.appendChild(meta).appendChild(source)
document.getElementsByClassName("meta")[i + nodelist]
.appendChild(date)

Remove all HTML <button> elements with regex

I'm trying to build a program to run a function every time I press a button, and output the returned value. To do this, I use the following HTML:
<h2>Test Results:</h2>
<strong><span id='runs'>0</span> tests</strong><br>
<div id='testResults'>
<button id='test' onClick='this.parentNode.innerHTML = initiatePlanB()'>Begin</button>
</div>
Here's the javascript:
var tests = document.getElementById('runs');
var inner = document.getElementById('testResults').innerHTML;
//Here's the part I can't figure out
var wo = inner.replace(??????, '');
var out = wo + '<br><strong>Test #' + String(Number(tests.innerText) + 1) + '</strong><br>';
tests.innerText = Number(tests.innerText) + 1;
//More stuff here
return out;
Basically, I need either a regex expression, or some other function that can remove any html tag and it's contents.
Why not just find all buttons using getElementsByTagName('button')
and then remove them all?
var testCount = 0;
var tests = document.getElementById('runs');
var inner = document.getElementById('testResults')
function initiatePlanB() {
var buttons = inner.getElementsByTagName('button');
if (buttons) {
for (var i = 0; i < buttons.length; i++) {
buttons[i].remove();
}
}
testCount++;
inner.insertAdjacentHTML('beforeend', '<br><strong>Test #' + testCount + '</strong><br>');
tests.innerText = testCount;
//More stuff here
}
<h2>Test Results:</h2>
<strong><span id='runs'>0</span> tests</strong><br>
<div id='testResults'>
<button id='test' onClick='initiatePlanB()'>Begin</button>
</div>
Though you should probably just hide the buttons, or disable them.

Send value of button to JS to load DIV content

I am trying to send the value of the selected option to an new DIV to dynamic load an drop down menu.
The DIV is triggered but the needed value is not send to this new DIV.
The problem is + $("#add_bedrijf_" + [i]).val()
What is the correct wat to send this?
(The other code is for manipulating the different classes, this is working correct.)
<div class="form-group col-md-6">
<div class="form-group has-warning-add has-feedback" id="div_add_bedrijf" data-toggle="buttons">';
$c = 0;
foreach ($_SESSION['bedrijf'] as $value)
{
echo '<label class="btn btn-secondary" for="add_bedrijf_<?php echo $c;?>"><input type="radio" id="add_bedrijf_<?php echo $c;?>" name="add_bedrijf" value="'.$value.'" onmousemove="validate_add()" onblur="validate_add()"><img src="images/logo_'.$value.'_small.png" height="30"></label>';
$c++;
}
echo '<span class="glyphicon glyphicon-warning-sign form-control-feedback" id="add_bedrijf_status"></span>
</div>
</div>
<script type="text/javascript">
function validate_add()
{
// Parent div of all buttons
let div_add_bedrijf = document.getElementById('div_add_bedrijf');
// Status div
let add_bedrijf_status = document.getElementById('add_bedrijf_status');
// A list with all the inputs that start the with id "add_bedrijf_"
let elements = document.querySelectorAll('input[id^="add_bedrijf_"]');
for(let i = 0; i < elements.length; i++) {
let element = elements[i];
// If the element is checked
if(element.checked) {
div_add_bedrijf.className = "form-group has-success has-feedback";
add_bedrijf_status.className = "glyphicon glyphicon-ok form-control-feedback";
$("#add_groep").load("includes/dynamic_drop/magazijn_magazijn_groep.php?choice=" + $("#add_bedrijf_" + [i]).val())
// We found one was selected, so exit the loop
return;
} else {
div_add_bedrijf.className = "form-group has-warning has-feedback";
add_bedrijf_status.className = "glyphicon glyphicon-warning-sign form-control-feedback";
}
}
}
</script>
Did you try + element.value instead of + $("#add_bedrijf_" + [i]).val()?
https://www.w3schools.com/jsref/prop_radio_value.asp

white screen shows while scroll down /up the

We get the data from server and append list view .our problem is while scroll up/down first it shows white screen then after shows data.
while scroll down/up the before coming white screen should remove
for (var i=0; i<len1; i++){
if (!listCreated) {
$("#ulcontent").append("<ul id='content' data-role='listview' data-split-icon='plus' data-split-theme='b' data-inset='true' class='ui-listview ui-listview-inset ui-corner-all ui-shadow'></ul>");
var listCreated = true;
$("#ulcontent").trigger("create");
}
var geImage=result.rows.item(i).Image;
var Custimage="";
if(geImage)
{
Custimage=result.rows.item(i).Image;
}
$('#content').append('<li class="ui-li-static ui-body-inherit ui-li-has-thumb ui-first-child"><img src='+appendurl+append+Custimage+'><p style="white-space: normal;"><b>Location:</b>'+result.rows.item(i).Location+'<br><b> Description:</b>'+ result.rows.item(i).Comments+'</p></a></li>');
}
When we remove images it's not showing any white screen.But we need image
Please tell to us what wrong in my code.
ThelistCreated variable in the if (!listCreated) statement and the listCreated variable in the var listCreated = true; statement are two different variables, so if (!listCreated) is always going to return false. That means means you're never actually creating the unordered list and then the list items are just getting displayed on the page background. So try moving listCreated to the outer scope like this:
var listCreated = false;
for (var i = 0; i < len1; i++) {
if (!listCreated) {
$("#ulcontent").append("<ul id='content' data-role='listview' data-split-icon='plus' data-split-theme='b' data-inset='true' class='ui-listview ui-listview-inset ui-corner-all ui-shadow'></ul>");
listCreated = true;
$("#ulcontent").trigger("create");
}
var geImage = result.rows.item(i).Image;
var Custimage = "";
if (geImage) {
Custimage = result.rows.item(i).Image;
}
$('#content').append('<li class="ui-li-static ui-body-inherit ui-li-has-thumb ui-first-child"><img src=' + appendurl + append + Custimage + '><p style="white-space: normal;"><b>Location:</b>' + result.rows.item(i).Location + '<br><b> Description:</b>' + result.rows.item(i).Comments + '</p></a></li>');
}

Categories

Resources