JQuery: Defining a variable is stopping my script from running - javascript

<script>
$(document).foundation(
var count = 1
$("button.test").click(function(){
if ($("p.change-me").text() === "OFF") {
$("p.change-me").text("ON")
count = count + 1
}
else if ($("p.change-me").text() === "ON") {
$("p.change-me").text("OFF")
count = count + 1
}
$("p.counter").text(count)
})
)
</script>
Very simply, I want to show the count as I am pressing this On and Off button. However, when I add the "var count = 1", my button no longer works. When I get rid of that line, the button will turn the text in the tag from ON to OFF and from OFF to ON.
How come? As you can probably tell, I am teaching myself JQuery.
Thanks!
HTML as requested:
<div class="row">
<div class="small-6 columns text-center">
<button class="button radius test">CLICK THIS</button>
</div>
<div class="small-6 columns text-center">
<p class="change-me">OFF</p>
</div>
</div>
<div class="row">
<div class="small-12 columns text-center">
<p>Here we will print how much fun you are having:</p>
<p class="counter">0</p>
</div>
</div>

Take your code out of the foundation() call. Also try to remember using semicolons.
$(document).foundation();
var count = 1;
$("button.test").click(function(){
if ($("p.change-me").text() === "OFF") {
$("p.change-me").text("ON");
count = count + 1;
}
else if ($("p.change-me").text() === "ON") {
$("p.change-me").text("OFF");
count = count + 1;
}
$("p.counter").text(count);
})

#Romain's answer is correct, but just to add to that... foundation is a method-call, and you were trying to put javascript code in the section where you normally put parameters (ie inside the ()). javascript code normally has to go inside of a function's body, not in the section where you type the parameters.

Related

Javascript loop to eliminate elements that do not start with certain value

I have links embedded inside .media-body .media-heading in the HTML example. I'm wanting to write JS to remove any link where the text does not start with the value attribute in the input element, in this case "A"
I've done a manual version below that checks the first A tag and manually removes the other A tag on the click of a button if the text doesn't start with "A". I need this to somehow loop through and do this automatically on page load but not sure how I do that. Any help is appreciated.
<!DOCTYPE html>
<html>
<body>
<input type="text" name="search" value="A" class="searchbox">
<div class="media-body">
<div class="media-heading">
A doc beginning with A
</div>
</div>
<div class="media-body">
<div class="media-heading">
Doc beginning with D
</div>
</div>
<button onclick="startFunction()">Remove wrong doc</button>
<script>
function startFunction() {
var az = document.getElementsByTagName("input")[0].getAttribute("value");
var getstart = document.getElementsByTagName("a")[0].innerHTML;
var searchletter = getstart.startsWith(az);
var myobj = document.getElementsByTagName("a")[1];
if(searchletter = az)
{
myobj.remove();
}
}
</script>
</body>
</html>
The second part of your question as how to do this automatically on page load is answered rather quickly. Conveniently you already wrapped the functionality inside it's own function - startFunction(). So all you have to do is execute that function after the <body> definition of your html code.
The first part isn't much more difficult as you also almost have anything you need set up yet. The only thing that's missing is looping over the HTMLCollection - more or less an array - retrieved by executing document.getElementsByTagName("a") using a simple for-loop.
There's a catch though: as you loop over the HTMLCollection and eventually remove an object from the DOM using .remove() you're ultimately changing the collection too. In other words, if you remove an object, the list shrinks by one element. To compensate your loop needs to start with the initial number of elements and decrement by one.
Here's an example:
function startFunction() {
let az = document.getElementsByTagName("input")[0].getAttribute("value");
let elements = document.getElementsByTagName("a");
let element;
for (let a = elements.length - 1; a >= 0; a--) {
element = elements[a];
if (!element.innerHTML.startsWith(az)) {
element.remove();
}
}
}
startFunction();
<input type="text" name="search" value="A" class="searchbox">
<div class="media-body">
<div class="media-heading">
A doc beginning with A
</div>
</div>
<div class="media-body">
<div class="media-heading">
Doc beginning with D
</div>
<div class="media-body">
<div class="media-heading">
Something completely different
</div>
</div>

Count and display most recent blog posts in javascript

What is the javascript in order to only display posts 3 & 4 in order???
Also I need it be dynamic so if I put a 5th post it will only display 4th and 5th posts... I was thinking about something like a date function or a simple incrementor but can't seem to figure it out. I'm new to javascript and have been trying different things but no avail... Thanks in advance...
<!DOCTYPE html>
<html>
<body>
<div id="posts-div">
<h1 class="post-title">post4</h1>
<p class="post">post4</p>
</div>
<div id="posts-div">
<h1 class="post-title">post3</h1>
<p class="post">post3</p>
</div>
<div id="posts-div">
<h1 class="post-title">post2</h1>
<p class="post">post2</p>
</div>
<div id="posts-div">
<h1 class="post-title">post1</h1>
<p class="post">post1</p>
</div>
<script>
// ???
</script>
</body>
</html>
You dont need script for that. You can do it with CSS.. I have changed your html little bit (made posts-div class in html).
.posts-div{
display:none;
}
.posts-div:nth-child(-n+2) {
display:block;
}
<!DOCTYPE html>
<html>
<body>
<div class="posts-div">
<h1 class="post-title">post5</h1>
<p class="post">post5</p>
</div>
<div class="posts-div">
<h1 class="post-title">post4</h1>
<p class="post">post4</p>
</div>
<div class="posts-div">
<h1 class="post-title">post3</h1>
<p class="post">post3</p>
</div>
<div class="posts-div">
<h1 class="post-title">post2</h1>
<p class="post">post2</p>
</div>
<div class="posts-div">
<h1 class="post-title">post1</h1>
<p class="post">post1</p>
</div>
<script>
// ???
</script>
</body>
</html>
You can test it on JSfiddle as well.. https://jsfiddle.net/nimittshah/b5eL3ykx/6/
$('.posts-div:gt(1)').hide()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<body>
<div class="posts-div">
<h1 class="post-title">post4</h1>
<p class="post">post4</p>
</div>
<div class="posts-div">
<h1 class="post-title">post3</h1>
<p class="post">post3</p>
</div>
<div class="posts-div">
<h1 class="post-title">post2</h1>
<p class="post">post2</p>
</div>
<div class="posts-div">
<h1 class="post-title">post1</h1>
<p class="post">post1</p>
</div>
</body>
Try this:
<script>
document.addEventListener("DOMContentLoaded", function () {
var allPosts = document.querySelectorAll(".posts-div");
// This is the number of posts you want displayed
var numberOfPostsToShow = 2;
for (var i = 0; i < allPosts.length; i++) {
if(i > numberOfPostsToShow - 1) {
allPosts[i].style.display = "none";
}
}
});
</script>
This way you will choose how many posts you want to be shown with the numberOfPostsToShow variable.
Let me know if this worked. Regards.
The way I interpreted your question, you need a way to:
show only the first n elements;
add new elements to the top of the list of posts, dynamically;
when you add them, update the visible elements.
Assuming a slightly modified version of your code, which corrects the id/class issue and adds a container for all the posts (this time with a proper id):
<!DOCTYPE html>
<html>
<body>
<div id="posts-container">
<div class="posts-div">
<h1 class="post-title">post4</h1>
<p class="post">post4</p>
</div>
<div class="posts-div">
<h1 class="post-title">post3</h1>
<p class="post">post3</p>
</div>
<div class="posts-div">
<h1 class="post-title">post2</h1>
<p class="post">post2</p>
</div>
<div class="posts-div">
<h1 class="post-title">post1</h1>
<p class="post">post1</p>
</div>
</div>
<script>
// ???
</script>
</body>
</html>
this code will do the trick and manage both the addition and the updates to the visibility of the posts:
function showOnly(visible, query){
var elements = document.querySelectorAll(query);
for (var i = 0; i < elements.length; i++){
if (i < visible - 1){
elements[i].style.display = 'block';
} else {
elements[i].style.display = 'none';
}
}
}
function publishPost(element, visible){
showOnly(visible, '#posts-container .posts-div')
var elements = document.querySelectorAll('#posts-container .posts-div');
element.style.display = 'block';
if (elements.length > 0) {
document.querySelector('#posts-container').insertBefore(element, elements[0]);
} else {
document.querySelector('#posts-container').appendChild(element);
}
}
The showOnly function (to be called with the number of elements to be shown and the string that identifies the elements with querySelectorAll) will only make visible the first n elements identified by the string. You can use it independently of the rest of the code if needed.
The publishPost function, on the other hand, is strictly dependent on the modified html above (to use it elsewhere you will need to adjust the strings fed to querySelector and querySelectorAll). It takes the element to be published as the first argument, the number of elements that need to be visible as the second. Then it updates the list of posts prepending the new one to it, and it also updates which posts are visible.
This is a code sample that uses it:
var elDiv = document.createElement('div');
var elH1 = document.createElement('h1');
var elP = document.createElement('p');
elDiv.classList = 'posts-div';
elH1.classList = 'post-title';
elP.classList = 'post';
elH1.innerText = 'some title';
elP.innerText = 'some text for the post';
elDiv.appendChild(elH1).appendChild(elP);
publishPost(elDiv, 2);
showOnly
This function starts by getting a list of the elements whose visibility must be managed:
var elements = document.querySelectorAll(query);
then it loops through the list and examines each element:
for (var i = 0; i < elements.length; i++){
if it has to be visible, it sets the style.display property to 'block':
if (i < visible){
elements[i].style.display = 'block';
otherwise it sets it to 'hidden':
else {
elements[i].style.display = 'none';
publishPost
This function starts by showing only n-1 elements (because it will need to add a new, visible element to the top of the list):
showOnly(visible - 1, '#posts-container .posts-div')
then it retrieve the current posts:
var elements = document.querySelector('#posts-container .posts-div');
it makes the new element visible:
element.style.display = 'block';
finally, it adds the element to the top of the list (the different syntax depends on wether the list is empty):
if (elements.length > 0) {
document.querySelector('#posts-container').insertBefore(element, elements[0]);
} else {
document.querySelector('#posts-container').appendChild(element);
}

Cutting down to 20 words with HTML content using JS and VueJS?

I am creating a news feed with VueJS and I have run into a bit of a problem with rendering the content. The API I am using sadly I am unable to change to suit my need properly at this time. The API gives me all the content already in HTML tags and it can also include images and lists and all the other basics. What I want to do is create a "read more" section which will render the first 20 words if just the text of the first "p" tag and stop there.
Does anyone know a quick and efficient way of doing this with JS?
My current display VueJS render is the following:
<div v-for="news_item in news_items">
<div v-bind:class="{ 'col-md-4': display}">
<div class="card">
<div class="header">
<h2>
{{news_item.title}} <small>{{news_item.subtitle}}</small>
</h2>
</div>
<div class="body" style="padding-top: 0">
<div class="row" style="margin-right: -20px; margin-left: -20px;">
<div class="col-md-12"
style="padding-left: 0px; padding-right: 0px;">
<img :src="news_item['thumbnail']"
class="img-responsive smaller-img" alt=""
style=" margin: 0 auto; max-height: 250px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<div v-html="news_item.content"></div>
</div>
</div>
</div>
</div>
</div>
</div>
This is the perfect time to use a directive:
https://v2.vuejs.org/v2/guide/custom-directive.html
See the codepen here: https://codepen.io/huntleth/pen/GOXaLo
Using the trim directive, you can change the content of the element. In the example above, it will show the first 5 words followed by an ellipsis.
If you're just after a pure js solution, this should do it:
var resultString = str.split(' ').slice(0, 20).join(" ");
You could use the trim directive and search the el for any p tags, and then change their content accordingly.
You don't appear to have tried anything yet, so I'll just give you these pointers. If you run into specific problems, ask again.
Make a component
The component should receive the html as a prop
The component should have a data item to control whether it is expanded
The component should have a computed that gets the first 20 words of the first paragraph tag. You can use textContent to get text from an HTML node.
The computed is the most likely part to pose a challenge. It will look something like this
blurb() {
const div = document.createElement('div');
div.innerHTML = this.content; // this.content is the prop
const firstP = div.querySelector('p');
const text = firstP.textContent;
const match = text.match(/(\S+\s*){0,20}/);
return match[0];
}
Rough implementation, Pure Js approach
document.getElementById("addContent").onclick = display;
document.getElementById("ellipsAnchor").onclick = hideEllipsis;
function display() {
document.getElementById("instruction").classList+= " hide";
let content = document.getElementById("inputbox").value;
if(content.length > 30) {
let sliced = content.slice(30);
let unsliced = content.substring(0,29);
let spantag = document.createElement("span");
spantag.className = "toReplace hide"
let text = document.createTextNode(sliced);
spantag.appendChild(text);
let spantag1 = document.createElement("span");
let text1 = document.createTextNode(unsliced);
spantag1.appendChild(text1);
let contentTag =document.getElementById("content");
contentTag.appendChild(spantag1)
contentTag.appendChild(spantag)
document.getElementById("ellipsis").classList -= "hide";
}
}
function hideEllipsis(){
document.getElementById("ellipsis").classList += " hide";
document.querySelectorAll("span.hide")[0].classList -= " hide"
}
.hide {
display : none;
}
<textarea type="text" id="inputbox"></textarea>
<button id="addContent">
Show content
</button>
<div id="content">
</div>
<div class="hide" id="ellipsis">
Read More..
</div>
<div id="instruction">
Type more than 30 characters and click show content
</div>
You can write a vue directive to solve this.
Set max-height to the div.
count the words and append "Read more.." link to the content.
Add a click event to 'read more' to expand the DIV to full height.
For example see this codepen
let handler = ""
Vue.directive("viewmore", {
inserted: function (el, binding){
let maxlines = binding.value
let lineheight = parseFloat(getComputedStyle(el).lineHeight)
let paddingtop = parseFloat(getComputedStyle(el).paddingTop)
let lines = (el.clientHeight) / lineheight ;
let maxheight = (lineheight * maxlines) + paddingtop + (lineheight/5)
if(lines>maxlines){
el.classList.add('vmore')
el.style.maxHeight = maxheight + 'px'
el.addEventListener('click', handler = ()=> {
el.style.maxHeight = ""
el.scrollIntoView({behavior: "smooth"})
el.removeEventListener('click', handler)
el.classList.remove('vmore')
})
}
},
unbind: function (el, binding) {
el.removeEventListener('click', handler)
handler = ""
}
});
https://codepen.io/dagalti/pen/vPOZaB .
it works based on the lines in the content.
Code : https://gist.github.com/dagalti/c8fc86cb791a51fe24e5dc647507c4a3
Expanding on the answers by tom_h and Roy J, here's what I'm using in my vue application to make the ellipsis clickable:
Vue.component("ellipsis", {
template: "#ellipsis-template",
props: ['content'],
data: function() {
return {
wordLength: 3, // default number of words to truncate
showAll: false
}
}
});
<script type="text/x-template" id="ellipsis-template">
<span v-if="content.split(' ').length>wordLength && showAll">{{content}}
(less)
</span>
<span v-else-if="content.split(' ').length>wordLength && !showAll">
{{content.split(" ").slice(0,wordLength).join(" ")}}
...
</span>
<span v-else>{{content}}</span>
</script>
To call it:
<ellipsis :content="someData"></ellipsis>

javascript if a html element text equal with 0, addClass to an element

I have an element that contains the discount of a product
<div class="discount_discountAmount">
<div id="mydiscouttext" class="discouttext">0
<span class="price_percent">%</span>
</div>
</div>
I want, if the element with id="mydiscouttext" equal to 0, addClass "hide".
I am looking for a solution with javascript.
Any idea?
I did something similar for another person, where I the table row had to be highlighted in the case of value in a cell being <=5. Please see if this helps you: https://codepen.io/nitinsuri/pen/WoqLzX
$(document).ready(function(){
$("table#book-list").find("td").each(function(){
var quantity = parseInt($.trim($(this).text()));
if(quantity <= 5){
$(this).parent("tr").addClass("low-quantity");
}
});
});
changes to:
<div class="discount_discountAmount">
<div id="mydiscouttext" class="discouttext">
<span class="value_percent">0</span>
<span class="price_percent">%</span>
</div>
</div>
and:
$(document).ready(function(){
var discouttext = $('#mydiscouttext span:first-child').html();
if(discouttext === '0')
$('.discount_discountAmount').hide();
});
if(!parseInt(document.querySelector("#mydiscouttext").innerText)){
document.querySelector("#mydiscouttext").style.display = "none";
}
this can be help
there, in plain Javascript,
var discount = document.getElementById('ammount').innerHTML;
console.log(discount);
if(parseInt(discount) <= 0 ) {
document.getElementsByClassName('discount_discountAmount')[0].classList.add("hide");
}
<div class="discount_discountAmount">
<div id="mydiscouttext" class="discouttext"><span id="ammount">0</span>
<span class="price_percent">%</span>
</div>
</div>
Also, i added a span to isolate the percentage amount. it's easy to deal with it then.
I would recommend to put it inside a span like the percent and try to put make a javascript like this
<div>
<span id="mydiscouttext">0</span>
<span>%</span>
</div>
<script>
$( document ).ready(function(){
var text = $("#mydiscouttext").html();
if(text == "0")
$("#mydiscouttext").hide();
});
</script>

Cannot access certain div class using jQuery

Brief synopsis of what I am doing: As of now I am trying to build a 6 x 6 grid and get some sign of life when I click on any of the grid boxes.
The result I want for now, is by clicking in any of the boxes I get a console message saying a piece was picked.
My main goal is to be able to differentiate between which box I picked, but first I need to figure it out generally.
HTML:
<div class="container">
<div class="row">
<div class="btn btn-lg btn-success col-lg-offset-4 col-md-4" id="makeBoard">Generate Board</div>
</div>
<div id="spacer"></div>
<div class="row">
<div class="col-md-12" id="newBoard"></div>
</div>
</div>
JQuery:
$(function(){
$('#makeBoard').click(function() {
var boardSize = 6;
makeBoard(boardSize);
});
function makeBoard(boardSize){
for(i = 0; i < boardSize; i++){
$('#newBoard').append("<div class='row' id='row"+i+"'>");
var row = "#row"+i;
for(j = 0; j < boardSize; j++){
var content = "<div class='col-md-2 boardPiece' id='"+i+"_"+j+"'></div>";
$(row).append(content);
}
$('#newBoard').append("</div>");
}
}
$('div.boardPiece').click(function() {
console.log("You clicked a piece!");
});
});
I double checked the html output by inspecting the element and indeed all the squares have the class 'boardPiece' but whenever I click on anywhere in the grid nothing gets logged in the console.
However, I have tried to console log the id 'newBoard' by clicking anywhere in the box and that worked. I'm assuming it has something to do with the boardPiece not being hardcoded in using HTML like newBoard is?
I'm using JS/JQuery so I can eventually change the board size from a form.
Thank you in advance.
Edit (Answer Below)
//Changed from this
$('div.boardPiece').click(function() {
console.log("You clicked a piece!");
});
//To this
$('.row').on("click", "div.boardPiece", function() {
console.log("You clicked a piece!");
});

Categories

Resources