Reputation: 541
I'm trying to give translateX()
property to cloned element which is called this.firstClone
as javascript. The problem is this.firstClone
doesn't refer to the cloned element even the value itself makes the clone in the code.
constructor($el) {
this.$el = $el; // 0
this.myCards = this.$el.find('a'); // 1
this.myCount = 1; // 2
this.myLength = this.myCards.length; // 3
this.firstClone = this.myCards.first().before(this.myCards.last().clone().addClass('cloned')); // 4 this makes the clone.
this.lastClone = this.myCards.last().after(this.myCards.first().clone().addClass('cloned'));
}
Above there, this.firstClone
makes the clone of the last image to the first in the set. And also when I remove that, the cloned element is gone. There's no problem to make, set or remove the cloned image.
But when I console.log
it, it refers second element which has translateX(1%)
in DOM. The property is also going to set to the second element when I do like this: this.firstClone.style.transform = "translateX(" + (-1) + "%)";
Is this a glitch of javascript? or do I just misunderstanding about .first()
and .clone()
method?
My goal is to give the css properties each of the cloned elements, but I stuck in here w/o no clues.
Full Code:
'use strict';
(function ($, window, undefined) {
$.fn.cardSlider = function(options) {
return this.each(function() {
const $el = $(this);
var thatCards = new Card($el, options);
thatCards.scrolling($el);
})
}
class Card {
constructor($el) {
this.$el = $el; // 0
this.myCards = this.$el.find('a'); // 1
this.myCount = 1; // 2
this.myLength = this.myCards.length; // 3
this.firstClone = this.myCards.first().before(this.myCards.last().clone().addClass('cloned')); // 4 this makes the clone.
this.lastClone = this.myCards.last().after(this.myCards.first().clone().addClass('cloned'));
}
scrolling($el) {
console.log(this.firstClone);
this.firstClone.style.transform = "translateX(" + (-1) + "%)"; // Browser fires an error. Cannot set property 'transform' of undefined
this.firstClone.css({
paddingBottom: 200 + 'px'
}); // An example for proving that the css property doesn't refer to the real clone.
for (var i = 0; i < this.myLength; i++) {
this.myCards[i].style.transform = "translateX(" + Math.pow(2, i) + "%)";
}
}
}
}(jQuery));
$('.outer').cardSlider();
.outer {
margin: 0 auto;
width: 70%;
overflow: hidden;
}
.film {
display: flex;
flex-flow: row;
justify-content: center;
left: 90%;
}
.images {
position: relative;
display: block;
width: 90%;
flex-shrink: 0;
padding-bottom: 74%;
background-color: blue;
}
.images:first-child, .images:last-child {
background-color: orange;
opacity: .4;
}
<div class="outer">
<div class="film">
<a class="images" href="#" draggable="false"></a>
<a class="images" href="#" draggable="false"></a>
<a class="images" href="#" draggable="false"></a>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
*I tested this code in Codepen and here but both didn't work. You probably have to make the new files to test this.
Upvotes: 0
Views: 1042
Reputation: 809
Your code is quite messy, but I think one problem you have is that you assign the wrong element to firstClone
and lastClone
. You propably want those variables to be references to the new clones, but that's not what your code does.
Let's look at this line:
this.firstClone = this.myCards.first().before(this.myCards.last().clone().addClass('cloned'));
First, you clone the last card and add the class cloned
(this.myCards.last().clone().addClass('cloned')
)
Then, you pass that clone to the function before
of the first card (this.myCards.first().before(...)
)
Finally, you assign whatever the function before
returns to the variable this.firstClone
The problem is that the expression a.before(b)
inserts b
before a
and then returns a
. What you want to save, though, is a reference to b
, not a
.
You have to use the function insertBefore
instead. It does exactly the same as before
, but the other way around: b.insertBefore(a)
also inserts b
before a
, but this returns b
.
(See the difference here: https://www.mkyong.com/jquery/jquery-before-and-insertbefore-example/)
So the line we looked at should be:
this.firstClone = this.myCards.last().clone().addClass('cloned').insertBefore(this.myCards.first());
This way, your variable this.firstClone
holds a reference to the newly created clone and not the (previously) first element. The same holds for the line after that:
this.lastClone = this.myCards.first().clone().addClass('cloned').insertAfter(this.myCards.last());
I hope this solves your problem.
Used in context:
'use strict';
(function ($, window, undefined) {
$.fn.cardSlider = function(options) {
return this.each(function() {
const $el = $(this);
var thatCards = new Card($el, options);
thatCards.scrolling($el);
})
}
class Card {
constructor($el) {
this.$el = $el; // 0
this.myCards = this.$el.find('a'); // 1
this.myCount = 1; // 2
this.myLength = this.myCards.length; // 3
this.firstClone = this.myCards.last().clone().addClass('cloned').insertBefore(this.myCards.first()); // 4 this makes the clone.
this.lastClone = this.myCards.first().clone().addClass('cloned').insertAfter(this.myCards.last());
}
scrolling($el) {
console.log(this.myCards[1]); // Both refers the same element
this.firstClone.css({
paddingBottom: 200 + 'px'
});
for (var i = 0; i < this.myLength; i++) {
this.myCards[i].style.transform = "translateX(" + Math.pow(2, i) + "%)";
}
}
}
}(jQuery));
$('.outer').cardSlider();
.outer {
margin: 0 auto;
width: 70%;
overflow: hidden;
}
.film {
display: flex;
flex-flow: row;
justify-content: center;
left: 90%;
}
.images {
position: relative;
display: block;
width: 90%;
flex-shrink: 0;
padding-bottom: 74%;
background-color: blue;
}
.images:first-child, .images:last-child {
background-color: orange;
opacity: .4;
}
<div class="outer">
<div class="film">
<a class="images" href="#" draggable="false"></a>
<a class="images" href="#" draggable="false"></a>
<a class="images" href="#" draggable="false"></a>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Upvotes: 1
Reputation: 782693
The problem is that this.firstClone
is a jQuery object, not a DOM element. But style
is a DOM property. In jQuery you use the .css()
function to add styles, so it should be:
this.firstClone.css("transform", "translateX(-1%)");
or you can put it as part of the following:
this.firstClone.css({
paddingBottom: 200 + 'px',
transform: "translateX(-1%)"
});
Your code works in the for
loop because when you index a jQuery collection, it returns the corresponding DOM element (to get the jQuery object, you use .eq(i)
). So you could also write the above as:
this.firstClone[0].style.transform = "translateX(-1%)";
Upvotes: 0