Javascript function doesn't do a transition - javascript

I want to make my list in my nav to have the transition applied.
The call
animate(0,"mainNav",.04,0.03);
The function
function animate(num, element, transitionUnit, delayUnit){
var transition = 0;
var delay = 0;
var x = document.querySelectorAll('nav > ul > li');
for (i=0; i<x.length; i++){
x[i].style.WebkitTransform = "translate3d("+num+"px,0px,0)";
x[i].style.opacity = "1";
x[i].style.transition = transition + "s " + delay +"s !important";
delay += delayUnit;
transition += transitionUnit;
}
}
This function applies changes to everything except that It just completely misses x[i].style.transition = ""; and x[i].innerHTML = "";
What could be the problem? I've tried changing everything including the querySelector, but this is what I've had found to work except the two I have mentioned above.
P.S. It works with
animate(0,"viewNav",.04,0.03);
I just need it to work with mainNav

Related

Vanilla Javascript: Infinite Image Marquee

Okay so I must create an infinite auto-scrolling horizontal image marquee using vanilla JS. I have the following code:
//if(painkiller<14){painkiller++;} else{painkiller=0;backup2()}
var speed = 5;
var exeggcute = true;
var painkiller = 0;
var marquix = document.getElementById("marquis");
var backup = "";
var coquus = 0;
for (var painkiller = 0; painkiller < 15; painkiller++) {
backup += "<img class='slide' src='" + ImgArray[painkiller].src + "' width='" + ImgArray[painkiller].width + "'>";
}
marquix.innerHTML = backup;
function riverflow() {
marquix.scrollLeft += 5;
if (marquix.children[0].getBoundingClientRect().left <= (marquix.children[0].width * -1)) {
marquix.appendChild(marquix.children[0]);
//marquix.getBoundingClientRect().left=0;
//marquix.children[0].style.transform="translateX(133px)"
}
}
//function backup2(){marquix.innerHTML=backup;}
setInterval('riverflow()', 50);
exeggcute = true;
<head>
<script>
var ImgArray = [];
for (var i = 0; i < 15; i++) {
ImgArray[i] = new Image();
ImgArray[i].src = "imgx/imagen" + (i + 1) + ".jpg";
ImgArray[i].width = 133;
}
</script>
</head>
<body>
<div id="marquis">
</div>
</body>
Basically I'm creating the image chain, then filling with it the innerHTML of a div, then assigning said div to a variable, and finally calling a repetitive function through setInterval(). Now, what that function does is a simple scroll to the left and - when the first image is completely out of the viewport - use appendChild to rip the first child element or img from the image chain then put it at the end of it. So no image overcharge is produced and the marquee uses the same 15 element once and again.
Here's my problem, though: when the appendChild function fires, the image that's out of the viewport is removed, however, the next image in line - as well as the rest of the chain - does not preserve its current position, and is instead forcefully scrolled to fill the gap left by the then-first image that's now at the end. Thus, the condition of the appendChild (which was the first children of the div being completely out of the viewport) becomes true and activates the function - leading the whole marquee to slide non-stop and out of control, as the appendChild is firing continuously.
How can I fix it?
Possible solutions:
You will need to reset the scrollLeft to 0 on the same moment that you switch the images.
You will need to add some element (another img for example at the begining) it could be all white or transparent. That image will be always there, before the firstone visible. When you remove the other image this auxiliar image need to be wider (change the width) to fill the gap, so add to its width the width of the removed image each time you remove one.
Or you can change the marginLeft of the leftmost image with marquix.children[0].style.marginLeft = n + "px";
That's what I came up with, but as I said, the translateX() parameter increases ad infinitum.
<script>
var ImgArray=[];
for (var i=0; i<15; i++){
ImgArray[i]= new Image();
ImgArray[i].src= "imgx/imagen"+(i+1)+".jpg";
ImgArray[i].width=133;
}
</script>
</head>
<body>
<div id="marquis">
<script>
//if(painkiller<14){painkiller++;} else{painkiller=0;backup2()}
var exeggcute= true;
var painkiller=0;
var marquix = document.getElementById("marquis");
var backup=""; var coquus=0;
for(var painkiller =0;painkiller<15;painkiller++){
backup+="<img class='slide' src='"+ImgArray[painkiller].src+"' width='"+ImgArray[painkiller].width+"'>";
}
marquix.innerHTML=backup;
var slidin=133;
function riverflow(){
marquix.scrollLeft+=10;
if (marquix.children[0].getBoundingClientRect().left<=(marquix.children[0].width*-1) && exeggcute){
marquix.appendChild(marquix.children[0]);
marquix.getBoundingClientRect().left=0;
for (var j=0; j<15; j++){
marquix.children[j].setAttribute("style","transform: translateX("+slidin+"px)")
}
slidin+=133;
}
}
//function backup2(){marquix.innerHTML=backup;}
setInterval('riverflow()',50);
exeggcute=true;
</script>

How to get the elements class name from a dynamically created element?

I started creating some minor code within my site, and i wanted to do some dynamic creation, so some span tags are created using a javaScript for loop.
In the same code, but a different loop i want to add an Event Listener to the tags.The error i get is the element created is non existent, and i have a few ideas why it's not working, but searching the Web and Stack Overflow gave me no answers.
I've considered putting both for loops into a function and calling that function in a similar fashion jquery works with it's document ready function. But i don't think that will fix the issue
var country = ["is_AmericaN", "is_Europe",
"is_Africa","is_AmericaS","is_Asia","is_Australia"];
var spanInto = document.getElementById("spanSelect");
for(i=0; i<6; i++)
{
var spanMake = document.createElement("SPAN");
spanInto.appendChild(spanMake);
spanMake.className += "spanLanguage" + " " + country[i];
}
The code above creates the elements, the code below tries to call them
var countryClass = doucment.getElementsByClassName("spanLanguage");
for(i=0; i< document.countryClass.length; i++)
{
countryClass[i].addEventListener("click", function(){
var hrDisplay = document.getElementById("selectiveDisplay");
hrDisplay.removeAttribute("id");
hrDisplay.className = "noDisplay";
},false);
}
I expect the working code to, once clicked on any span tag, set the display of the hr tag to block or flex. I dont want to create 5-6 span tags manually, it has to be a dynamic creation.
You are missing the position of the adding class
var spanMake = document.createElement("SPAN");
spanInto.appendChild(spanMake);
spanMake.className += "spanLanguage" + " " + country[i];
Here you are assigning the class after appending it into span, that is wrong you need to assign class before.
var countryClass = doucment.getElementsByClassName("spanLanguage");
for(i=0; i< document.countryClass.length; i++)
{
doucment is document and document.countryClass should be countryClass as you already have the instance of the element
var country = ["is_AmericaN", "is_Europe",
"is_Africa", "is_AmericaS", "is_Asia", "is_Australia"
];
var spanInto = document.getElementById("spanSelect");
for (i = 0; i < 6; i++) {
var spanMake = document.createElement("SPAN");
spanMake.textContent = country[i];
spanMake.className += "spanLanguage" + " " + country[i];
spanInto.appendChild(spanMake);
}
var countryClass = document.getElementsByClassName("spanLanguage");
for (i = 0; i < countryClass.length; i++) {
countryClass[i].addEventListener("click", function() {
var hrDisplay = this;
hrDisplay.removeAttribute("id");
hrDisplay.className = "noDisplay";
}, false);
}
.noDisplay {
display: none;
}
<span id="spanSelect"></span>
<br/>
//click on any of them to replace the class
There are multiple points to be corrected:
There was a type "doucment" in your code.Use "document" instead.
Created elements didn't have any text on it, how will you call click
on element when it is not visible in DOM.
Events are attached to anchors/button not span.
Not sure what you are trying to do by attaching events.
below is the code snippet which works for you when you try to add events on dynamic created elements.Let me know if you need further help
function temp() {
var country = ["is_AmericaN", "is_Europe",
"is_Africa", "is_AmericaS", "is_Asia", "is_Australia"
];
var spanInto = document.getElementById("spanSelect");
for (i = 0; i < 6; i++) {
var spanMake = document.createElement("a");
spanMake.innerHTML = country[i];
spanInto.appendChild(spanMake);
spanMake.className += "spanLanguage" + " " + country[i];
}
}
function attachEvent() {
var countryClass = document.getElementsByClassName("spanLanguage");
for (i = 0; i < countryClass.length; i++) {
countryClass[i].addEventListener("click", function(event) {
console.log("I am called" + event.target);
//var hrDisplay = document.getElementById("selectiveDisplay");
//hrDisplay.removeAttribute("id");
//hrDisplay.className = "noDisplay";
}, false);
}
}
a {
padding: 20px;
}
<body>
<div id="spanSelect"></div>
<div id="selectiveDisplay"> </div>
<button onclick="temp()"> Call Me </button>
<button onclick="attachEvent()"> Attach Event </button>
</body>

Flipping a div by class name

I'm trying to flip a div on mouseover, I found a few pages really useful.
followed this to set ID and then according to this one I need to add the mouseover property in the HTML but it's not easy as the ID.
Here is my code so far:
var abcElements = document.querySelectorAll('.builder_row_cover');
for (var i = 0; i < abcElements.length; i++)
abcElements[i].id = 'abc-';
var oHover = document.getElementById("abc-");
oHover.setAttribute("onmousehover", "flip()");
var k = 0;
function flip() {
var j = document.getElementById("abc-");
k += 180;
j.style.transform = "rotatey(" + k + "deg)";
j.style.transitionDuration = "0.5s"
}
I'm just starting, I have tried with setting attribute, but no way to see the mouseover in the HTML, any suggestion?
First, the name of the event is onmouseover.
Giving multiple elements the same ID won't work. document.getElementById() will just return the first element with that ID, not the one that the mouse is over.
You don't need to use the ID at all. You can use this in the event handler to refer to the target of the event.
var abcElements = document.querySelectorAll('.builder_row_cover');
for (var i = 0; i < abcElements.length; i++) {
abcElements[i].addEventListener('mouseover', flip);
}
var k = 0;
function flip()
k += 180;
this.style.transform = "rotatey(" + k + "deg)";
this.style.transitionDuration = "0.5s";
}

Slide dynamically added content with jQuery

I'm trying to create a simple content slider that could handle dynamically added content to the slider. None of the "lightweight" plugins I found provided such functionality or, if it did, it didn't work correctly.
var $left = $('.left'),
$right = $('.right'),
$months = $('.sub ul');
$left.click(function(){
for(i = 0; i < 3; i++){
$months.find('li').first().before($.parseHTML('<li>xxx</li>'));
}
pos = $months.position();
$months.css('left', pos.left + 90);
});
$right.click(function(){
for(i = 0; i < 3; i++){
$months.find('li').last().after($.parseHTML('<li>xxx</li>'));
}
pos = $months.position();
$months.css('left', pos.left - 90);
});
This is the code I've got so far and here's a fiddle with an example - http://jsfiddle.net/kkr4zg0r/2/. It kind of works, but the problem is that since new content is added the navigation goes off (you can see what I mean by clicking left-right a couple of times).
I understand what's the problem for this - the newly added items "shift" the content and I need to do better calculations than substracting/adding 90px to the left position of the element but I can't figure out how to get the correct index of the elements and basically get this sliding by exactly (and correctly) by 3(or 6) elements at the time.
Currently the code is adding extra elements whenever a navigation button is pressed, if I could get the index of the currently visible first/last element, I could probably tell whether I need to add more elements and only add them then.
This is a basic illustration of what I'm trying to achieve
edit
I've changed the jsfiddle to the correct one.
The whole idea is to check when adding elements is necessary and when shift is enough:
Fiddle
$(document).ready(function()
{
var $main = $('.main'),
$left = $('.left'),
$right = $('.right'),
$months = $('.sub ul');
var addCount = 3;
var liWidth = 30;
var shiftX = addCount * liWidth;
$left.click(function()
{
var currentLeft = parseInt($months.css('left'));
var totalLength = $months.find('li').length * liWidth;
if (-currentLeft + $main.width() >= totalLength)
{
for (var i = 0; i < addCount; i++)
{
$months.find('li:last').after('<li>xxx</li>');
}
}
$months.css('left', currentLeft -= shiftX);
});
$right.click(function()
{
var currentLeft = parseInt($months.css('left'));
if (currentLeft < 0)
{
$months.css('left', currentLeft += shiftX);
}
else
{
for (var i = 0; i < addCount; i++)
{
$months.find('li:first').before('<li>xxx</li>');
}
}
});
});

Pre-formatting text to prevent reflowing

I've written a fairly simple script that will take elements (in this case, <p> elements are the main concern) and type their contents out like a typewriter, one by one.
The problem is that as it types, when it reaches the edge of the container mid-word, it reflows the text and jumps to the next line (like word wrap in any text editor).
This is, of course, expected behavior; however, I would like to pre-format the text so that this does not happen.
I figure that inserting <br> before the word that will wrap would be the best solution, but I'm not quite sure what the best way to go about doing that is that supports all font sizes and container widths, while also keeping any HTML tags intact.
I figure something involving a hidden <span> element, adding text to it gradually and checking its width against the container width might be on the right track, but I'm not quite sure how to actually put this together. Any help or suggestions on better methods would be appreciated.
Edit:
I've managed to write something that sort of works using jQuery, although it's very sloppy, and more importantly, sometimes it seems to skip words, and I can't figure out why. #content is the name of the container, and #ruler is the name of the hidden <span>. I'm sure there's a much better way to do this.
function formatText(html) {
var textArray = html.split(" ");
var assembledLine = "";
var finalArray = new Array();
var lastI = 0;
var firstLine = true;
for(i = 0; i <= textArray.length; i++) {
assembledLine = assembledLine + " " + textArray[i];
$('#ruler').html(assembledLine);
var lineWidth = $('#ruler').width();
if ((lineWidth >= $('#content').width()) || (i == textArray.length)) {
if (firstLine) { var tempArray = textArray.slice(lastI, i); }
else { var tempArray = textArray.slice(lastI+1, i); }
var finalLine = tempArray.join(" ");
finalArray.push(finalLine);
assembledLine = "";
if (lineWidth > $('#content').width()) { i = i-1; }
lastI = i;
firstLine = false;
}
}
return finalArray.join("<br>");
}
You could use the pre tag: Which displays pre-formatted text, or you could put the content into a div tag, set a fixed width, and script based upon that.
The best way (IMO) would be to add the whole word, but have the un-"typed" letters invisible. E.g:
H<span style="visibility: hidden;">ello</span>
He<span style="visibility: hidden;">llo</span>
Hel<span style="visibility: hidden;">lo</span>
Hell<span style="visibility: hidden;">o</span>
Hello
To make it easier, give the span a name, and delete it from the DOM each time.
A possible approach is to set p display inline (because default display-block will make p to consume all width even if it has just 1 character) and then as you 'type' check the element width.
Set a tolerance in px (25px for example) and once p's width reaches total available width minus width tolerance you insert <br />
I think this should work...
After playing with the code I edited into the question, I managed to get it working decently.
Code:
function formatText(html) {
var textArray = html.split(" ");
var assembledLine = "";
var finalArray = new Array();
var lastI = 0;
var firstLine = true;
for(i = 0; i <= textArray.length; i++) {
assembledLine = assembledLine + " " + textArray[i];
$('#ruler').html(assembledLine);
var lineWidth = $('#ruler').width();
if ((lineWidth >= $('#content').width()) || (i == textArray.length)) {
if (firstLine) { var tempArray = textArray.slice(lastI, i); }
else { var tempArray = textArray.slice(lastI+1, i); }
var finalLine = tempArray.join(" ");
finalArray.push(finalLine);
assembledLine = "";
if (lineWidth >= $('#content').width()) { i = i-1; }
lastI = i;
firstLine = false;
}
}
return finalArray.join("<br>");
}
Not perfect, but it'll do. Thanks, everyone.

Categories