How can I store a string without duplicating it? - javascript

There are 2 cards panels, and I would like to change the image of the card when I hover over it, then when I leave it I want to come back to the initial image.
First time it works for each image, but when I try to hover second time it duplicates my string where I store the path..
HTML CODE
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0"">
<img src="img/slide-1.jpg" class=" card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Image 1</h5>
</div>
</div>
</div>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0"">
<img src="img/slide-1.jpg" class=" card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Image 2</h5>
</div>
</div>
</div>
JQUERY CODE
(function ($) {
"use strict"; // Start of use strict
var image_product;
var image_product_path="/Users/paul/Desktop/Site/";
$(".card-img-top").on({
mouseenter: function () {
image_product = $(this).attr("src");
$(this).attr("src","/Users/paul/Desktop/Site/img/slide-3.jpg");
},
mouseleave: function () {
$(this).attr("src",image_product_path+image_product);
}
});
})(jQuery); // End of use strict
The error that is triggered second time when I try to hover over the cards:
[Error] Not allowed to load local resource: file:///Users/paul/Desktop/Site//Users/paul/Desktop/Site/img/slide-1.jpg
The error that is triggered third time when I try to hover over the cards:
[Error] Not allowed to load local resource: file:///Users/paul/Desktop/Site//Users/paul/Desktop/Site//Users/paul/Desktop/Site//Users/paul/Desktop/Site/img/slide-1.jpg
AND SO ON

There are n cards panels, and I would like to change the image of the
card when I hover over it, then when I leave it I want to come back to
the initial image.
Set the original image into a data attribute, then on mouse out switch it back.
(function($) {
$(".card-img-top").on({
mouseenter: function() {
$(this).data('original', $(this).attr("src"));
$(this).attr("src", "https://via.placeholder.com/300/09f/000.png");
},
mouseleave: function() {
$(this).attr("src", $(this).data('original'));
}
});
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0">
<img src="https://via.placeholder.com/300/09f/fff.png" class=" card-img-top " alt="... ">
<div class="card-body ">
<h5 class="card-title ">Image 1</h5>
</div>
</div>
</div>
If you want a different image for each different card then set it into a data attribute.
(function($) {
$(".card-img-top").on({
mouseenter: function() {
$(this).data('original', $(this).attr("src"));
$(this).attr("src", $(this).data('hover-image'));
},
mouseleave: function() {
$(this).attr("src", $(this).data('original'));
}
});
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0">
<img src="https://via.placeholder.com/100/09f/fff.png" data-hover-image="https://via.placeholder.com/100/09f/000.png" class=" card-img-top " alt="... ">
<div class="card-body ">
<h5 class="card-title ">Image 1</h5>
</div>
</div>
</div>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0">
<img src="https://via.placeholder.com/100/07f/aaa.png" data-hover-image="https://via.placeholder.com/100/05f/333.png" class=" card-img-top " alt="... ">
<div class="card-body ">
<h5 class="card-title ">Image 2</h5>
</div>
</div>
</div>

Here's what the src attribute and your image_product variable contain at the different phases:
Phase
src
image_product
before first run
img/slide-1.jpg
undefined
first mouseenter
/Users/paul/Desktop/Site/img/slide-3.jpg
img/slide-1.jpg
first mouseleave
/Users/paul/Desktop/Site/img/slide-1.jpg
img/slide-1.jpg
2nd mouseenter
/Users/paul/Desktop/Site/img/slide-3.jpg
/Users/paul/Desktop/Site/img/slide-3.jpg
2nd mouseleave
/Users/paul/Desktop/Site/Users/paul/Desktop/Site/img/slide-1.jpg
/Users/paul/Desktop/Site/img/slide-3.jpg
In your handlers functions, you keep storing whatever is in src into image_product when the mouse enters.
The second time you mouseenter, image_product already contains the full path, but in your mouseleave function you keep prepending the path every time.

Please check a link
https://stackoverflow.com/a/18032363/3526623
The solution from the link above without Jquery
function hover(element) {
element.setAttribute('src', 'http://dummyimage.com/100x100/eb00eb/fff');
}
function unhover(element) {
element.setAttribute('src', 'http://dummyimage.com/100x100/000/fff');
}
<img id="my-img" src="http://dummyimage.com/100x100/000/fff" onmouseover="hover(this);" onmouseout="unhover(this);" />

Related

Vue 3 dynamic image

I am using a v-for to load data on cards. The image is not showing up and not sure why.
I though :src = "'item.img'" or :src = "{{item.img}}" would work, but neither are working.
Here is my code
<div v-for="(item, index) in basicData" :key="index">
<transition class="slide">
<div v-if="index >= start && index < end" class="card">
<div class="card-body">
<h5 class="card-title">{{item.title}}</h5>
<img
:src="'item.img'"
class="card-img-top"
:alt="'item.img'"
style="margin: 20px 5px"
/>
<p class="card-text">Some quick example text.</p>
</div>
</div>
</transition>
and here is the screen shot
When I hard code src="../assets/featured/pizzaOne.jpeg"
the image appears.
You can create method or computed property:
methods() {
getImage(imagePath) {
return require(imagePath);
}
}
Then in template call that method:
<img
:src="getImage(item.img)"
class="card-img-top"
:alt="item.img"
style="margin: 20px 5px"
/>

jQuery-ui weird behavior with sortable after an element is dropped

I'm building a system that would allow a user to drag and drop elements from a dragzone to a dropzone. Once dropped, the elements are cloned "back" to their origin. Also, the user can sort the elements dropped as he wants.
I had a first issue where I couldn't clone the block I dragged, but I could sort it when it was dropped. Now that I fixed the clone problem, if I try to sort the elements, the elements moving come from the dragzone and I can't understand why.
Here is the HTML:
<div class="container-fluid">
<div class="row">
<div class="card col-3">
<div class="card-body">
<div class="card draggable-element" data-target="textarea">
<div class="card-body">
This is some text within a card body. 1
</div>
</div>
<div class="card draggable-element" data-target="textfield">
<div class="card-body">
This is some text within a card body. 2
</div>
</div>
<div class="card draggable-element" data-target="fileinput">
<div class="card-body">
This is some text within a card body. 3
</div>
</div>
</div>
</div>
<div class="card col-6 offset-1">
<div class="card-body dropzone">
</div>
</div>
</div>
</div><!-- /.container -->
And here is the JS:
$(document).ready(function() {
$('.draggable-element').draggable({
revert: 'invalid',
appendTo: '.dropzone',
helper: 'clone'
});
$('.dropzone').droppable({
drop: function (event, ui) {
// With the following code, the elements won't get cloned
var item = $(ui.draggable);
if(!item.hasClass('copy')) {
item.clone().addClass('copy');
item.draggable({
revert: 'invalid',
stack: ".draggable",
helper: 'clone'
})
}
else {
$(this).append($(ui.helper).clone());
}
$(this).append(item);
}
})
.sortable();
});
/*
drop: function (event, ui) {
// With the following code, the elements getting sorted are
// the div.draggable-element from the div.card.col-3
$(ui.draggable).clone(true).detach().css({
position: 'relative',
top: 'auto',
left: 'auto'
}).appendTo(this);
}
*/
I haven't used jquery-ui for a while so I can't find what may be obvious, I tried to mix the code together but it didn't end up well at all.
Thank you in advance
OK, this is likely NOT a full answer ( but the markup had an odd "card-body" holder of cards so I renamed that to test. Does Not "clone" as was represented in the question...so it sorts in my example but not sure this totally reproduces/resolves here. I updated the "clone" part but not sure it is what you desire.
$(document).ready(function() {
$('.draggable-element').draggable({
revert: 'invalid',
appendTo: '.dropzone',
helper: 'clone'
});
$('.dropzone').droppable({
drop: function(event, ui) {
// With the following code, the elements won't get cloned
var item = $(ui.draggable);
// hide to not obscure console.log(item.length);
if (!item.hasClass('copy')) {
var newy = item.clone(false);
newy.addClass('copy');
//console.log(newy);
newy.draggable({
revert: 'invalid',
stack: ".draggable",
helper: 'clone'
});
} else {
$(this).append(item);
}
$('.dropzone').append(newy);
// $(this).append(item);
}
})
.sortable();
});
.cards,
.dropzone {
border: solid red 1px;
height: 5em;
}
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="container-fluid">
<div class="row">
<div class="card col-3">
<div class="cards">
<div class="card draggable-element" data-target="textarea">
<div class="card-body">
This is some text within a card body. 1
</div>
</div>
<div class="card draggable-element" data-target="textfield">
<div class="card-body">
This is some text within a card body. 2
</div>
</div>
<div class="card draggable-element" data-target="fileinput">
<div class="card-body">
This is some text within a card body. 3
</div>
</div>
</div>
</div>
<div class="card col-6 offset-1">
<div class="card-body dropzone">
</div>
</div>
</div>
</div>

Angular ngFor - restriction to show on every item

I have got following code in my component.html. ( I am new to angular )
<div class="card" *ngFor="let item of galleries;"
(mouseenter)=" setBackground(item?.image?.fullpath)"
(mouseover)="showCount = true; getImagesCount(item.path);" (mouseleave)="showCount = false">
<img class="card-img-top" [routerLink]="['/'+item.path]"
[src]="item?.image?.fullpath ? path + '0x156/' + item?.image?.fullpath : defaultImage"
alt="Card image cap">
<div class="card-block">
<h4 class="card-title imagesCount"></h4>
<h4 class="card-title title">{{item.name}}</h4>
<img class="closeIcon" src="../../../assets/images/close.png" alt="" (click)="removeGallery(item);">
<span class="animated fadeInUp" *ngIf="showCount">{{imagesCount}}</span>
</div>
</div>
Down in the code i have *ngIf="showCount where i am trying to show how many images gallery have. But issue is that it is shown on every card, but i want it to show only on current card that i enter my mouse with.
You should specify your *ngIf in:
<span class="animated fadeInUp" *ngIf="showCount">{{imagesCount}}</span>
because actually you will get for every item in your galleries list.
Here is an idea, how you can specify that:
Step 1: Add new variable to your component.ts
currentItem: number;
Step 2: add index to your ngFor
*ngFor="let item of galleries; let index = index;"
Step 3: Extend your (mouseover) and (mouseleave) events
Add currentItem and fill with data.
(mouseover)="showCount = true; currentItem = index; getImagesCount(item.path);"
(mouseleave)="showCount = false; currentItem = null;"
Step 4: Change you *ngIf in span with itemsCount
<span class="animated fadeInUp" *ngIf="showCount && currentItem == index">{{imagesCount}}</span>
Now you have a spicified solution.
I would suggest you to create an extra key i.e. showCount inside item object.
item = {
...,
showCount: false
}
than use that key for showing and hiding showCount in the HTML.
<div class="card" *ngFor="let item of galleries;"
(mouseenter)=" setBackground(item?.image?.fullpath)"
(mouseover)="item[showCount] = true; getImagesCount(item.path);"
(mouseleave)="item[showCount] = false">
<img class="card-img-top" [routerLink]="['/'+item.path]"
[src]="item?.image?.fullpath ? path + '0x156/' + item?.image?.fullpath : defaultImage"
alt="Card image cap">
<div class="card-block">
<h4 class="card-title imagesCount"></h4>
<h4 class="card-title title">{{item.name}}</h4>
<img class="closeIcon" src="../../../assets/images/close.png" alt="" (click)="removeGallery(item);">
<span class="animated fadeInUp" [hidden]="item[showCount]">{{imagesCount}}</span>
</div>
</div>
I would approach this by making your 'showCount' variable into an array, and comparing *ngIf to the array value:
Some small tweaks:
<div class="card" *ngFor="let item of galleries; let idx=index">
....
(mouseover)="showCount[idx]=true
(mouseleave)="showCount[idx]=false
</div>
...
<span class="animated fadeInUp" *ngIf="showCount[idx]">

How to shorten this code?

I'm trying to create on() mouseenter function for each element, but is there any way to shorten that function somehow. The problem is that I've created that on mouseenter function several times. Please help guys :)
This is the code below
var $member1 = $('.team-content img:nth-child(1)'),
$member2 = $('.team-content img:nth-child(2)'),
$member3 = $('.team-content img:nth-child(3)'),
$member4 = $('.team-content img:nth-child(4)')
$(".member1").on('mouseenter', function() {
$member1.css({
"left": "0px"
});
}).on('mouseleave', function() {
$member1.css({
"left": ""
});
});
$(".member2").on('mouseenter', function() {
$member2.css({
"left": "0px"
});
}).on('mouseleave', function() {
$member2.css({
"left": ""
});
});
$(".member3").on('mouseenter', function() {
$member3.css({
"left": "0px"
});
}).on('mouseleave', function() {
$member3.css({
"left": ""
});
});
$(".member4").on('mouseenter', function() {
$member4.css({
"left": "0px"
});
}).on('mouseleave', function() {
$member4.css({
"left": ""
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="team" class="about-team">
<div class="team-header">
<h2 class="team-text">Our Team</h2>
<div class="divider"></div>
</div>
<div class="section-content">
<div class="row text-center">
<div class="col-xs-6 col-md-3 col-lg-3 member1">
<h2 class="t-seperator">John Doe</h2>
<span>/CEO</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member2">
<h2 class="t-seperator">Jesica Ice</h2>
<span>/DESIGNER</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member4">
<h2 class="t-seperator">Anna Moon</h2>
<span>/MARKETER</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member3">
<h2 class="t-seperator">Michael Huge</h2>
<span>/DEVELOPER</span>
</div>
</div>
</div>
</div>
<div id="main-team" class="team-content">
<img src="assets/img/team/team1.jpeg" alt="Team 1">
<img src="assets/img/team/team2.jpg" alt="Team 2">
<img src="assets/img/team/team3.jpg" alt="Team 3">
<img src="assets/img/team/team4.jpg" alt="Team 4">
</div>
You can add a general handler and apply the function on the corresponding .member* element if you detect the index of the hovered img using the index() function, Here is an example: (In the example I change the color just for clarity)
$(".team-content img").on('mouseenter', function(e) {
var imageIndex = $(".team-content img").index(e.target) + 1;
$(".member" + imageIndex).css({
"color": "red"
});
}).on('mouseleave', function(e) {
var imageIndex = $(".team-content img").index(e.target) + 1;
$(".member" + imageIndex).css({
"color": "black"
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="team" class="about-team">
<div class="team-header">
<h2 class="team-text">Our Team</h2>
<div class="divider"></div>
</div>
<div class="section-content">
<div class="row text-center">
<div class="col-xs-6 col-md-3 col-lg-3 member1">
<h2 class="t-seperator">John Doe</h2>
<span>/CEO</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member2">
<h2 class="t-seperator">Jesica Ice</h2>
<span>/DESIGNER</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member4">
<h2 class="t-seperator">Anna Moon</h2>
<span>/MARKETER</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member3">
<h2 class="t-seperator">Michael Huge</h2>
<span>/DEVELOPER</span>
</div>
</div>
</div>
</div>
<div id="main-team" class="team-content">
<img src="assets/img/team/team1.jpeg" alt="Team 1">
<img src="assets/img/team/team2.jpg" alt="Team 2">
<img src="assets/img/team/team3.jpg" alt="Team 3">
<img src="assets/img/team/team4.jpg" alt="Team 4">
</div>
You can just use a loop to get them all done at once!
for (var i = 1; i <= 4; i++) {
$('.member' + i).on('mouseenter', function() {
$('.team-content img:nth-child(' + i + ')').css({'left': '0px'});
}).on('mouseleave', function() {
$('.team-content img:nth-child(' + i + ')').css({'left': ''});
});
}
I may have over-thought it, but if the member number and the nth-child number are the same, why not use that to create the relevant accessor? I've got three functions here: the first runs on initialization and saves the integer portion of the member number as a data attribute for later retrieval. The mouseenter and mouseleave functions retrieve that saved member number, and build the selector using that.
$("div[class*='member']").each(function() {
// for every member element, let's save its
// relevant nth-child number.
var myNumber = 0;
var myClasses = $(this).prop("class").split(" ");
// check all classes to find the member number
for (var i = 0; i <= myClasses.length; i++) {
if ( myClasses[i].startsWith("member") ) {
// strip out JUST the number portion.
myNumber = myClasses[i].match(/\d+/)[0];
}
if( myNumber != 0 )
break;
}
// Save the number portion for later.
$(this).data("nthNumber", myNumber);
}).on('mouseenter', function() {
// retrieve the saved number
var selector = ".team-content img:nth-child("+ $(this).data("nthNumber") +" )";
$(selector).show();
}).on('mouseleave', function() {
// retrieve the saved number
var selector = ".team-content img:nth-child("+ $(this).data("nthNumber") +" )";
$(selector).hide();
});
.about-team {
width: 400px;
float: left;
}
.team-content {
position: absolute;
right: 5px;
top: 5px;
}
.team-content img {
display: none;
border: 1px dotted red;
width: 100px;
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="team" class="about-team">
<div class="team-header">
<h2 class="team-text">Our Team</h2>
<div class="divider"></div>
</div>
<div class="section-content">
<div class="row text-center">
<div class="col-xs-6 col-md-3 col-lg-3 member1">
<h2 class="t-seperator">John Doe</h2>
<span>/CEO</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member2">
<h2 class="t-seperator">Jesica Ice</h2>
<span>/DESIGNER</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member4">
<h2 class="t-seperator">Anna Moon</h2>
<span>/MARKETER</span>
</div>
<div class="col-xs-6 col-md-3 col-lg-3 member3">
<h2 class="t-seperator">Michael Huge</h2>
<span>/DEVELOPER</span>
</div>
</div>
</div>
</div>
<div id="main-team" class="team-content">
<img src="assets/img/team/team1.jpeg" alt="Team 1">
<img src="assets/img/team/team2.jpg" alt="Team 2">
<img src="assets/img/team/team3.jpg" alt="Team 3">
<img src="assets/img/team/team4.jpg" alt="Team 4">
</div>
So a few changes made: first, I'd left the initial selector wrong. Then, I added some CSS styles so we could see something happening. The advantage of this approach (while it may be longer) is that it's extensible. If you add thirty more employees, you'd have to create a variable for each one, and use that each time. By this approach, it's happening automatically.

JavaScript array skipping values

I have this function that loops through all of the <img> tags and adds their sourcesrc into an array. When the user clicks on the main parent div, Bootstrap's modal fades in showing the rest of the gallery.
My problem is, whenever I press the right chevron on a specific div it shows the gallery and slides them perfectly but when I click on another div, the array skips two values and displays the third one instead.
To explain my problem more briefly, lets say I have this array:
arr = [1,2,3,4,5]
When I click the next button the first time it works perfectly
1 => 2 => 3 => 4 => 5
But when I click on another div and press next:
1 => 2 => 5
Here's a working demo of what I have done till now.
HTML:
<div class="col-md-4 col-sm-4 col-lg-4 padBtm10">
<a data-toggle="modal" data-target="#exampleModal" href="#" class="modal-trigger deco-none" onclick="return false;">
<div class="card that_img radius10">
<img data-caption-title="First caption" class="card-img-top img-responsive caption" src="http://dummyimage.com/500x300/000/fff" alt="Card image cap" />
<span class="fa fa-search search fa-3x blue"></span>
<div class="redbg radiusBtm10 white card-block">
<h4 class="card-title">Lorem Ipsum</h4>
</div>
<div class="imgs-album">
<img src="http://dummyimage.com/500x300/000/fff" class="img-responsive full" data-caption-title="First caption for slider 1" />
<img src="http://dummyimage.com/500x300/ddd/fff" class="img-responsive full" data-caption-title="First caption for slider 2" />
<img src="http://dummyimage.com/500x300/aaa/fff" class="img-responsive full" data-caption-title="First caption for slider 3" />
<img src="http://dummyimage.com/500x300/ccc/000" class="img-responsive full" data-caption-title="First caption for slider 4" />
</div>
</div>
</a>
</div>
update (HTML structure for the modal)
<div class="modal breaker fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body noPad">
<button type="button" class="close-pop close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<div class="">
<a href="#" onclick="return false;">
<span class="fa fa-chevron-right fa-2x right white"></span>
</a>
<a href="#" onclick="return false;">
<span class="fa fa-chevron-left fa-2x left white"></span>
</a>
</div>
<div class="pop-image">
<img src="" class="img-responsive full">
</div>
<h4 class="modal_caption"></h4>
</div>
</div>
</div>
</div>
JavaScript:
(function() {
var ready = function() {
$(".that_img").hover(function() {
$(this).find("span.search").css("display", "block");
}, function() {
$(this).find("span.search").css("display", "none");
});
$(".that_img").on({
click: function() {
var img_src_arr = $(this).find(".imgs-album")
.children("img").map(function() {
return $(this).attr("src");
}).get();
var img_data_cap = $(this).find(".imgs-album")
.children("img").map(function() {
return $(this).data("caption-title");
}).get();
$(".pop-image").find("img").attr("src", img_src_arr[0]);
$(".modal_caption").html(img_data_cap[0]);
var counter = 0;
counter >= 0 ? $(".left").hide() : $(".left").show();
$(".right").on({
click: function() {
counter += 1;
if (counter == 1) {
$(".left").show()
}
var next = $(".pop-image").find("img")
.attr("src", img_src_arr[counter]);
var next_cap = $(".modal_caption")
.html(img_data_cap[counter]);
if (counter > (img_src_arr.length - 2)) {
$(".right").hide();
$(".left").show();
}
}
});
$(".left").on({
click: function() {
counter -= 1;
$(".right").show();
if (counter === 0) {
$(".right").show();
$(".left").hide();
}
$(".pop-image").find("img")
.attr("src", img_src_arr[counter]);
var prev = $(".modal_caption").html(img_data_cap[counter]);
}
});
}
});
}
$(document).ready(ready);
}).call(this);
The problem occurs because every time an image is clicked, click-handlers are added. With the first image everything seems fine because .left and .right have, at that point, a single click handler. Upon clicking another image, new click-handlers are added and now when you click a chevron, the 2 handlers are being executed resulting in your counter going up, or down, by 2 instead of 1. To prevent this from happening you will have to unbind the handlers from the object.
Change these lines, (explanation here)
$(".right").on({
$(".left").on({
to,
$(".right").off().on({
$(".left").off().on({
And change this line,
counter >= 0 ? $(".left").hide() : $(".left").show();
to,
$(".right").show()
$(".left").hide()
Edit : as mentioned by juhana unbind() is deprecated, so use off() instead.

Categories