I am trying to add a class to an image after determining if it is landscape or portrait. The problem I am having is that the class is being added to the img tag like this img.landscape which is obviously not registering properly. How can I properly achieve this: <img class="landscape" ?
$(data.images).each(function(j, imageURL){
var thumbnail = new Image();
thumbnail.src = imageURL;
thumbnail.onload = function() {
$('.images').append('<div class="image_mask"><img src="' + imageURL + '"/></div>');
if (thumbnail.width > thumbnail.height){
$(this).addClass('landscape');
}
};
});
My previous solution was to include an if/else statement with the class added in the appended string, but I am wondering if there is a cleaner way of approaching this. Thanks!
EDIT--
http://jsfiddle.net/curly33/XeHzK/1/
I'm assuming you want to add a class to the <img> tag you're dynamically creating a few lines before? If so, you can do so like this:
$('.image_mask img').addClass('landscape');
Since it's in a loop and you'll have multiple div.image_mask, use the array index j as a class qualifier:
$(data.images).each(function(j, imageURL){
...
thumbnail.onload = function() {
$('.images').append('<div class="image_mask image_mask' + j + '"><img src="' + imageURL + '"/></div>');
// ^^^^^^
if (thumbnail.width > thumbnail.height){
$('.image_mask' + j + ' img').addClass('landscape');
// ^^^^^^
}
};
});
UPDATE
Even though this was accepted, it feels clumsy to me to add class names like I originally suggested. A cleaner approach would be to use the j array index variable in combination with jQuery's eq function to locate the relevant image mask:
$('.images .image_mask').eq(j).addClass('landscape');
..then do away with the whole adding of classes approach.
Just put it in your string building
$(data.images).each(function(j, imageURL){
var thumbnail = new Image();
thumbnail.src = imageURL;
thumbnail.onload = function() {
var orientationClass = thumbnail.width > thumbnail.height ? "landscape" : "portrait";
$('.images')
.append(
'<div class="image_mask"><a href="' +
imageURL +
'"><img class="' +
orientationClass +
'" src="' +
imageURL +
'"/></a></div>'
);
};
});
Edit: More options
If you want to make it more verbose, but cleaner, you could build out the elements one by one:
var $img = $('<img />', {
class: thumbnail.width > thumbnail.height ? "landscape" : "portrait",
src: imageUrl
});
var $a = $('<a />', {
href: imageUrl,
}).append($img);
var $div = $('<div />', {
class: "image_mask"
}).append($a);
$('.images').append($div);
Or if you want to use the more efficient string building, but what it to be more readable/performant, you could do an array with a join:
var contents = [
'<div class="image_mask"><a href="',
imageURL ,
'"><img class="',
orientationClass,
'" src="',
imageURL,
'"/></a></div>'];
$('.images').append(contents.join(''));
Related
I'm trying implement a like button that changes color when clicked. I am trying to replace the image dynamically using jQuery.
<div class = "col-sm-10" style = "margin-top: 2%">
<input style = "width : 4%; height: 4%" type = "image" id = {{schedule.id}} + "image" class = "likes"
data-scheduleid = "{{schedule.id}}" data-user = "{{curruser.person.id}}"
src = "{% static 'img/notliked2.png' %}"/>
</div>
This is image file that gets pressed as a button. Essentially, I am trying to change the image file on click.
$(document).ready(function() {
$('.likes').click(function(e){
var sched_id;
var curruser;
sched_id = $(this).attr("data-scheduleid");
curruser_id = $(this).attr("data-user");
$.get('/profiles/like_schedule/', {schedule_id: sched_id, current_user: curruser_id}, function(data){
var first = data.split("/")
$('#' + sched_id).html(first[0]);
console.log(first[1])
//$('#likes').html("<input style = 'width : 4%; height: 4%' type = 'image' id = {{schedule.id}} class = 'likes' data-scheduleid = '{{schedule.id}}' data-user = '{{curruser.person.id}}' src = {% static 'img/" + first[1] + "' %}/>");
$('.' + sched_id + "image").attr("src", "{% static 'img/" + first[1] + "' %}")
e.preventDefault();
});
});
});
This is the jQuery. I logged first[1], and it is correct. It alternates between "notliked2.png" and "liked2.png" when someone likes and unlikes. But for some reason replacing the image source doesn't work. I even tried replacing the entire html, and it still doesn't work. Does someone know what is going on?
Thank you,
Albert Jin
edit:
Here is the views code.
def like_schedule(request):
sched_id = None
if request.method == 'GET':
sched_id = request.GET['schedule_id']
curruser_id = request.GET['current_user']
likes = 0
liked = "liked2.png"
if sched_id:
sched = schedules.objects.get(id = int(sched_id))
curruser = person.objects.get(id = int(curruser_id))
if curruser in sched.person_likes.all():
liked = "notliked2.png"
sched.likes -= 1
sched.person_likes.remove(curruser)
else:
sched.likes += 1
sched.person_likes.add(curruser)
likes = sched.likes
sched.save()
return HttpResponse(str(likes) + "/" + str(liked))
As for the repeat posts, I did try those but they do not work.
You are using django sytax in your javascript code. You cant use the static function like this:
$('.' + sched_id + "image").attr("src", "{% static 'img/" + first[1] + "' %}")
I would replace the current url and only replace the dynamic part of the url, like so:
var src = $('.' + sched_id + "image").attr("src");
$('.' + sched_id + "image").attr("src", src.slice(0, src.indexOf('img/')) + 'img/" + first[1]);
Not sure of how is the format of the $.get response (you don't show it in the question), but looking at your code this should be enough...
$(document).ready(function() {
$('.likes').click(function(e) {
e.preventDefault();
var $img = $(this);
$.get('/profiles/like_schedule/',{ schedule_id: $img.data("scheduleid"), current_user: $img.data("user") }, function(data) {
$img.attr('src','img/' + data.split("/")[1])
});
});
});
One posible problem is that you're having a caching problem, so your get call is not being executed. If that's your case, you can force your server to execute that call just adding some extra inconstant parameter...
$.get('/profiles/like_schedule/',{ dummy: (new Date()).getTime(), schedule_id: $img.data("scheduleid"), current_user: $img.data("user") }, function(data) {
$img.attr('src','img/' + data.split("/")[1])
});
NOTE: When you want to get the value of a data-whatever attribute in jquery, you have the .data('whatever') function (is designed for that).
My ajax call returns this :(there are two images and the number of images may vary)
[{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/1.png"},
{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/completionist.png"}]
I am able to display the images in my UI as follows :
if (counter<=0){
$('#imagesofBadges').append('<img src="' + data[0].BadgeImage + '"/>');
$('#imagesofBadges').append('<img src="' + data[1].BadgeImage + '"/>');
counter++;
}
Problem :
The point is I dont want to use two append statements as the no of images returned by the ajax call may vary.It will depend on the condition set to pull the images from DB.The images are pulled from the same column name "BadgeImage" as can be seen in the ajax data.
The code I tried :
var $img = $('<img src="' + data[0].BadgeImage + '"/>'); // create the image
$img.addClass('badge-image'); // add the class .badge-image to it
$('#imagesofBadges').append($img); // append it
$('#imagesofBadges .badge-image'); // will fetch all the elements that have the class .badge-image that are inside #imagesofBadges.
Kindly help.
Try the following code using .each function
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
var data = '[{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/1.png"}, {"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/completionist.png"},{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/2.png"},{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/3.png"}]';
data = jQuery.parseJSON(data);
$.each(data, function( index, value ) {
var $img = $('<img class="badge-image" src="' + data[index].BadgeImage + '"/>'); // create the image
$('#imagesofBadges').append($img); // append it
});
$('#imagesofBadges .badge-image').each(function () {
alert($(this).attr('src'));
}); // will fetch all the elements that have the class .badge-image that are inside #imagesofBadges.
});
</script>
</head>
<div id="imagesofBadges">
</div>
Actually,I do not get your point.Maybe you can try this!
var data = [
{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/1.png"},
{"BadgeImage":"http:\/\/localhost:8666\/web1\/profile\/images\/badge image 2\/completionist.png"}];
var dom = data.map(function (value) {
return '<img src="' + value.BadgeImage + '"/>';
})
$('#imagesofBadges').append(dom.join(''));
try this :
$('#imagesofBadges').empty();
$.each(data, function(index, value) {
//Your code
});
keywords = [
"http://www.website-for-hair.com/",
"http://www.website-for-shoes.com/"
]
var keyword = keywords[Math.floor(Math.random()*keywords.length)]
document.write('<img src="http://i.imgur.com/test.jpg" title="Test Title" />');
The above code works perfectly however it spins only the domain. I am now required to add individual images for each website and then output domain+image using +keyword+ together?
Here's one way that's similar to how you did it before:
var websites = [
{ url: "http://site1.com", image: "http://site1.com/logo.png" },
{ url: "http://site2.com", image: "http://site2.com/logo.jpg" }
];
var website = websites[Math.floor(Math.random * websites.length)];
document.write(
'<a href="' + website.url + '">' +
'<img src="' + website.image + '" title="foo" />' +
'</a>'
);
You could use a list of lists.
Each list contained in that list would store the URL (position 0, keywords[random_index][0]) and its corresponding image source (position 1, keywords[random_index][1]).
You should also store the random index that you generate in a variable to ensure you always access the same sublist.
For example:
keywords = [
["http://www.website-for-hair.com/", "imgA"],
["http://www.website-for-shoes.com/", "imgB"]
]
var random_index = Math.floor(Math.random()*keywords.length);
var keyword = keywords[random_index][0];
var image = keywords[random_index][1];
document.write('<a href='+keyword+'><img src='+image+' title="Test Title" /></a>');
I am bringing a feed of a youtube user's video channel onto a page via two plugins called jYoutube and jGFeed.
jGFeed: http://archive.plugins.jquery.com/project/jgfeed
jYoutube: http://archive.plugins.jquery.com/project/jyoutube
I am getting stuck on why this isn't working... I thought it would be as easy as a simple if/else statement, but it is not working.
jQuery(document).ready(function($) {
$.jGFeed('http://gdata.youtube.com/feeds/base/users/POTATOwillEATyou/uploads?alt=rss&v=2&orderby=published&client=ytapi-youtube-profile',
function(feeds){
// Check for errors
if(!feeds){
// there was an error
return false;
}
var html = '';
// do whatever you want with feeds here
for(var i=0; i<feeds.entries.length; i++){
var entry = feeds.entries[i];
//My attempt at alternating classes:
if((i%2) == 0)
{
console.log('hello')
$(".thethumb").addClass("even");
}
else
{
console.log('NOPE')
$(".thethumb").addClass("odd");
}
//End of my attempt
html += '<a rel="vidbox" class="thethumb" target="_blank" href="' + entry.link + '" title="' + entry.title + '"><img src="' + $.jYoutube(entry.link, 'small') + '" class="thumb left"></a>';
}
$('#you_tube_feed').html(html);
}, 25);
});
Your issue is that you are are changing the class of ALL .thethumb, and they don't exist at the time you're running that code (they're inside your html string)
for(var i=0; i<feeds.entries.length; i++)
{
var entry = feeds.entries[i];
var $new = $('<a rel="vidbox" class="thethumb" target="_blank" href="' + entry.link + '" title="' + entry.title + '"><img src="' + $.jYoutube(entry.link, 'small') + '" class="thumb left"></a>');
if((i%2) == 0)
{
$new.addClass("even");
}
else
{
$new.addClass("odd");
}
$('#you_tube_feed').append($new);
}
Since you are using JQuery, it's even more simple . . . add all of the thumbnails first and then go back use the :even and :odd selectors to add the classes all at once:
$('.thethumb:even').addClass('odd');
$('.thethumb:odd').addClass('even');
You'll noticed that the classes are switched in comparison to the selectors . . . that is because the JQuery selector is 0-based, so items "0", "2", "4", etc. are actually the 1st, 2rd, 5th, etc. items in the selection.
I am wondering if there is a better way to write this JavaScript (Jquery) code.
This snippet dynamically created a H3 with a link.
My designer is going nuts trying to style this as its in JavaScript.
I am trying to re-write / refactor this into to smaller chunks to allow my designer to style without looking at all this code on one single line.
var dvClassContainer = $(document.createElement('div')).attr("id", 'dvclassconatiner_' + classVal).attr("classifname", classifname).attr("memclassnumber", memclassnumber).html('<h3>' + classifname + '<a id="ancclassremove_'+ classVal +'" classVal="' + classVal + '" onclick="RemoveClassificationUponConfirm(\'' + classVal + '\');" class="buttons delete btnSmall">Delete</a></h3><img style="display:none;" id="imgloadRemClass_' + classVal + '" alt="loading" src="../Images/application/smallUploading.gif" />');
I was thinking of creating more variables and combining them together.
Is there a 'cleaner' way of writing this?
If you utilize more of jQuery's features, the code becomes more readable and more easily maintained:
var dvClassContainer = $('<div>');
dvClassContainer.attr({
id: 'dvclasscontainer_'+classVal,
classifname: classifname,
memclassnumber: memclassnumber
});
var dvHeader = $('<h3>');
var dvHeaderLink = $('<a>Delete</a>');
dvHeaderLink.attr({
id: 'ancclassremove_'+classVal,
classVal: 'classVal',
class: 'buttons delete btnSmall'
}).on('click',function(){
RemoveClassificationUponConfirm(classVal);
});
var dvImg = $('<img>');
dvImg.attr({
id: 'imgloadRemClass_'+classVal,
alt: 'loading',
src: '../Images/application/smallUploading.gif'
});
dvClassContainer.append(dvHeader.append(dvHeaderLink.append(dvImg)));
Ideally, you would also want to move all those non-standard attributes (classifname, memclassnumber, classVal) to data- attributes, which would be accessible via jQuery's data() function.
var dvClassContainer = $(document.createElement('div'))
.attr("id", 'dvclassconatiner_' + classVal)
.attr("classifname", classifname)
.attr("memclassnumber", memclassnumber)
.html('<h3>' + classifname + '<a id="ancclassremove_'+ classVal +'" classVal="' + classVal + '" onclick="RemoveClassificationUponConfirm(\'' + classVal + '\');" class="buttons delete btnSmall">Delete</a></h3><img style="display:none;" id="imgloadRemClass_' + classVal + '" alt="loading" src="../Images/application/smallUploading.gif" />');
The last line still needs fixing. I would create elements and then set their attributes and then append them to the h3. You can do that using var h3 = $("<h3></h3>"); (as an example) and set attributes using .attr() and finally .append() to put it all together.
I'm going to go a different way with this, after acknowledging that this one line of code is nasty.
It's not the JavaScript that's giving your designer headaches. If they can't style this with CSS, they're not trying hard enough. Surely that h3 and anchor are inside other elements that they can grab for some styling:
.someContainer h3 { color: chartreuse; }
However, if they HAVE tried everything possible, you still just need to add a new class or two (to the h3 and the anchor). Where you have .html('<h3>'... you would change it to .html('<h3 class="someClass">'...
As much as we have fun optimizing and downright fixing bad JS in poor implementations, if we assume that this is "working", the problem is the designer's ability to style. This is therefore not really a JavaScript issue.
Use Douglas Crockford's Supplant method. It tokenizes a string so you can dynamically build strings out. Here is a fiddle example: http://jsfiddle.net/mmeah/F23rk/
// http://javascript.crockford.com/remedial.html
if (!String.prototype.supplant) {
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
}
var classVal="x", classifname="y", memclassnumber="z"; //predefined
var dvClassHtml = $("#someDiv").html();
$("#someDiv").html("");
var params ={
"classVal":classVal,
"classifname":classifname,
"memclassnumber":memclassnumber
};
dvClassHtml=dvClassHtml.supplant(params);
var dvClassContainer =
$(document.createElement('div'))
.attr("id", 'dvclassconatiner_' + classVal)
.attr("classifname", classifname)
.attr("memclassnumber", memclassnumber)
.html(dvClassHtml);
var dvClassContainer = $('<div/>')
.attr({'id': 'dvclassconatiner_' + classVal,
'classifname': classifname,
'memclassnumber': memclassnumber
})
.html(
function() {
var $title = $('<h3>' + classifname + '</h3>');
var $link = $('<a>Delete</a>').attr({
'id': 'ancclassremove_' + classVal,
'classVal': classVal,
'class': 'buttons delete btnSmall'
})
.on('click', function() {
RemoveClassificationUponConfirm(classVal);
});
var $img = $('<img/>').attr({
'id': 'imgloadRemClass_' + classVal,
'alt': 'loading',
'src': '../Images/application/smallUploading.gif'
})
.css('display', 'none');
return $title.append($link).add($img);
});
Demo