I am currently coding an instant chatbox using jquery which will show the latest chat on top (refreshes when user send data via post request)
and push the oldest chat downward and remove it.
The problem is that if more than one latest chat is retrieved(for example, 2), two new div will be prepended but only one oldest div is removed instead of two...I tried timeout but it didnt work either..
Below are the code snippets I believe which got problem in it.
function showData(currentchatstyle, data, final){
var newchatstyle;
if (currentchatstyle == "chatone") {
newchatstyle = "chattwo";
}
else {
newchatstyle = "chatone";
}
$('div[class^="chat"]:first').before('<div class="' + newchatstyle + '" style="display:none;">' + data + ' </div>');
$('div[class^="chat"]:first').slideDown(500,"swing", function(){
$('div[class^="chat"]').last().fadeOut(500, function() {
$(this).remove();
});
});
return newchatstyle;
}
$('input[name="content"]').keyup(function(key) {
if (key.which==13) {
var author = $('input[name="author"]').val();
var content = $('input[name="content"]').val();
var lastnum = $('postn:first').text();
var chatstyle = $('div[class^="chat"]:first').attr("class");
$.post(
"chatajax.php",
{ "author": author, "content": content, "lastnum": lastnum },
function(data) {
var msg = data.split("|~|");
for (var i = 0; i < msg.length; i++) {
chatstyle = showData(chatstyle, msg[i], true);
}
}
);
}
});
Help will be very much appreciated.
The problem is that you do select also currently-fading-out divs with $('div[class^="chat"]').last(), as you don't remove them immediately but in the animation callback. You for example might immediately remove the chat class so it won't be selected in the next call to showData.
Also, you should only use one class "chat" for a similar divs and for a zebra-style give them independent classes.
var chatstyle = "one";
function showData(data, final){
chatstyle = chatstyle=="one" ? "two" : "one";
var newDiv = $('<div class="chat '+chatstyle+'" style="display:none;">'+data+'</div>');
$('div.chat:first').before(newDiv);
newDiv.slideDown(500, "swing", function(){
$('div.chat:last').removeClass('chat').fadeOut(500, function() {
// ^^^^^^^^^^^^^^^^^^^^
$(this).remove();
});
});
}
function post(data) {
return $.post(
"chatajax.php",
data,
function(data) {
var msg = data.split("|~|");
for (var i = 0; i < msg.length; i++)
showData(msg[i], true); // what's "final"?
}
);
}
$('input[name="content"]').keyup(function(key) {
if (key.which==13)
post({
"author": $('input[name="author"]').val(),
"content": $('input[name="content"]').val(),
"lastnum": $('postn:first').text() // I'm sure this should not be extracted from the DOM
});
});
Related
I'm working on a project that returns GIFs from the GIPHY API, and whenever a search is executed, I'm capturing each search history item as its own button that a user can click on and see the results of the search as opposed to retyping the search again. I successfully added the buttons to the HTML with the proper classes, however, when I tried to write a simple on click event such as $('.history-btn').on('click', function() {
console.log('hello');
});
nothing appears. What is causing this? Here is my whole set of code for context:
$(document).ready(function () {
var searches = [];
function addSearch() {
$(".prev-searches").empty();
for (var i = 0; i < searches.length; i++) {
var history = $('<button>');
history.addClass("btn btn-primary history-btn");
history.attr("data-name", searches[i]);
history.text(searches[i]);
$(".prev-searches").append(history);
}
}
$('.history-btn').on('click', function() {
console.log('hello');
});
function returnSearch() {
var gifSearch = $(".search-input").val().trim();
var queryURL = 'https://api.giphy.com/v1/gifs/search?api_key=XXXXX-HIDDEN-XXXXX&q=' + gifSearch + '&limit=15&offset=0&rating=PG&lang=en';
$.ajax({
url: queryURL,
method: "GET"
}).then(function(response){
console.log(queryURL);
console.log(response);
console.log(response.data.length);
for (var i =0; i < response.data.length; i++) {
arrImg = response.data[i].images.fixed_width.url;
var newContent = '';
newContent = '<img src="' + arrImg + '">';
$('.gif-area').html(newContent);
console.log(newContent);
}
});
}
//When search is executed
$('.search-btn').on('click', function() {
event.preventDefault();
var search = $('.search-input').val().trim();
searches.push(search);
addSearch();
returnSearch();
});
function renderGIFs () {
for (var i = 0; i < response.data.length; i++) {
var newGifs = '';
newGifs += '<img src="' + response.data[i].bitly_gif_url + '"';
$(".gif-area").html(newGifs);
}
}
});
You need event delegation:
$('.prev-searches').on('click', '.history-btn', function() {
console.log('hello');
});
Resource
Understanding Event Delegation
Is the class 'history-btn' added dynamically from your addSearch function?
Then please use an element which is above in heirarchy of history-btn and bind the event to that element.
For example I bind the event to the div element,
<div id='historybtncontainer'>
<button class='history-btn'>Button</button>
</div>
and in script you can do
$('historybtncontainer').on('click', 'history-btn', function(){
console.log("hello");
});
document allows you to get a new tree of elements after dynamically adding the history-btn class to the <button>
$(document).on('click', '.history-btn', function() {
console.log('hello');
});
The appropriate bits of what I tried are here:
$(".popovers").mouseover( function()
{
//var mainTableBody = document.getElementById("subCriteriaTableBody");
var tableRows = document.getElementsByClassName("popoversBlock");
var i = 0, j = 0;
for (i = 0; i < tableRows.length; i++)
{
var labelList = tableRows[i].getElementsByTagName("label");
var tdList = tableRows[i].getElementsByClassName("popovers");
for (j = 0; j < labelList.length; j++)
{
if(labelList[j].parentElement.parentElement.rowIndex == tdList[j].parentElement.rowIndex)
{
attName = $(this).text();
var attributeName = attName.slice(0, -1);
$.ajax({
url:'/diganta/getPopoverValueReassignTaskOfUser.do?attributeName='+attributeName,
type:'post',
dataType: 'json',
success: function(data) {
$('.popovers').attr('data-content', data.PopoverValue);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Failed! Reason: "+ thrownError);
}
});
break;
}
else
{
continue;
}
}
}
});
When I mouse hover, I see the request get made, but doesn't populate the popover. I don't even see JSP page for the popover first time but second time it's ok get added to the DOM.
Please help me ....
Thanks in advance.
You need to call
$('.popovers').attr('data-content', data.PopoverValue).popover('show');
to show the Popover
Hope it will solve your problem...
Edit
$('#your_lable_id').attr('data-content', data.PopoverValue).popover('show');
If the problem appears at the first time only and it works afterwards, you are probably missing:
$(document).ready(function(){
...
});
Another advice, quoting W3C page:
Popovers are not CSS-only plugins, and must therefore be initialized with jQuery: select the specified element and call the popover() method.
currently i'm starting with Ember, and i'm loving it! I'm with some difficulties, especially when it comes to components.
For you to understand, I'm going through old code to Ember, and I would like to turn this code into a Component, but I do not know actually how to start, since I do not know how to catch the button being clicked, and I also realized that Ember has several helpers, maybe I do not need any of this giant code to do what I want.
This is the old code result: http://codepen.io/anon/pen/WQjobV?editors=110
var eventObj = {};
var eventInstances = {};
var actual;
var others;
var clicked;
var createEventInstance = function (obj) {
for (var key in obj) {
eventInstances[key] = new Event(obj[key]);
}
};
var returnStyle = function (inCommon) {
var $inCommon = inCommon;
$inCommon.css({
width: '342.4px',
minWidth: '342.4px'
});
$inCommon.find('.cta').removeClass('hidden');
$inCommon.find('.event-close').removeClass('inline');
$inCommon.find('.event-info_list').removeClass('inline');
$inCommon.removeClass('hidden');
$inCommon.find('.expanded').slideUp();
$inCommon.find('.expanded').slideUp();
$inCommon.find('.event-arrow').remove();
$inCommon.find('h2').find('ul').remove('ul');
};
var Event = function (id) {
this.id = id;
};
Event.prototype.expandForm = function () {
actual.css('width', '100%');
actual.find('.event-info_list').addClass('inline');
actual.find('.expanded').slideDown().css('display', 'block');
actual.find('.event-close').addClass('inline');
};
Event.prototype.close = function () {
returnStyle(actual);
returnStyle(others);
};
Event.prototype.hideElements = function () {
clicked.addClass('hidden');
others.addClass('hidden');
};
Event.prototype.maskPhone = function () {
$('[name$=phone]').mask('(99) 99999-9999', {
placeholder: '(00) 0000-0000'
});
};
$('.submit-form').on('click', function (e) {
e.preventDefault();
var id = '.' + $(this).data('id');
var name = $(id).children('#person-name').val();
var email = $(id).children('#person-email').val();
var guests = $(id).children('#person-obs.guests').val();
var phone = $(id).children('#person-phone').val();
var participants = $(id).children('#booking-participants').val();
if (name === '' || email === '' || phone === '' || participants === '' || guests === '') {
alert('Preencha os campos obrigatórios.');
} else {
$(id).submit();
}
});
Event.prototype.createDropDown = function () {
actual.find('h2').addClass('event-change')
.append('<span class="event-arrow" aria-hidden="true">â–¼</span>')
.append(function () {
var self = $(this);
var list = '<ul class="dropdown hidden">';
$('.event').each(function (index) {
if ($(this).find('h2')[0] != self[0]) {
list += '<li data-index="' + index + '">' + $(this).find('h2').text() + '</li>';
}
});
return list;
}).click(function () {
if ($(this).attr('data-expanded') == true) {
$(this).find('ul').toggleClass('hidden');
$(this).attr('data-expanded', false);
} else {
$(this).find('ul').toggleClass('hidden');
$(this).attr('data-expanded', true);
}
}).find('li').click(function (e) {
e.stopPropagation();
actual.find('.event-info_list').removeClass('inline');
actual.find('h2').attr('data-expanded', false);
actual.find('h2').removeClass('event-change');
actual.find('.expanded').slideUp().css('display', 'inline-block');
others.removeClass('hidden');
actual.find('.cta').removeClass('hidden');
actual.find('h2').find('.event-arrow').remove();
actual.find('h2').off('click');
actual.find('h2').find('ul').remove('ul');
$($('.event')[$(this).attr('data-index')]).find('.cta').trigger('click');
});
};
Event.prototype.open = function () {
actual = $('[data-id="' + this.id + '"]');
others = $('.event').not(actual);
clicked = actual.find('.cta');
this.hideElements();
this.expandForm();
this.createDropDown();
this.maskPhone();
};
$('.event').each(function (i, event) {
var prop = 'id' + $(event).data('id');
var value = $(event).data('id');
eventObj[prop] = value;
});
createEventInstance(eventObj);
Basically i have this boxes, which box represent one booking in some event (will be populate by the server). When the user clicks in one box, this boxes expands and the other disappear. But than a dropbox will be created with the other boxes, so the user can navigate in the events by this dropdown.
I didn't do much with Ember, i transform the "events" div into a component with the name "BookingBoxComponent" and two actions:
SiteApp.BookingBoxComponent = Ember.Component.extend({
actions:
open: function() {
// HOW COULD I ACCESS THE CLICKED BUTTON HERE?
},
close: function() {
}
});
As you can see, i put two actions, one for opening the box and other for closing, should i just put the logic in both, or i can improve this like a Ember way?
I don't know if i am asking to much here, so if i am, at least i would like to know how to access the button clicked in the open method, i was trying passing as a parameter, like:
<button {{action 'open' this}}></button>
But didn't work.
I could offer 50 of my points to someone who help transform the old cold in a Ember way code.
Thanks.
The event object will be passed with every action as the last parameter, so when you specified this you were actually passing whatever object has context in that block. In your open function, do not pass this and do
open: function(event) {
// event.currentTarget would be the button
}
And now you can do something like event.currentTarget or event.target
I have here a little script that I found and am using it to create a simple game of sorts...
/*
Here add:
'image_path': ['id_elm1', 'id_elm2']
"id_elm1" is the ID of the tag where the image is initially displayed
"id_elm2" is the ID of the second tag, where the image is moved, when click on the first tag
*/
var obimids = {
'http://www.notreble.com/buzz/wp-content/uploads/2011/12/les-claypool-200x200.jpg': ['lesto', 'les'],
'http://rs902.pbsrc.com/albums/ac223/walkingdeadheartbreaker/Muzak/Guitarists/LarryLalondePrimus.jpg~c200': ['lerto', 'ler'],
'http://www.noise11.com/wp/wp-content/uploads/2014/07/Primus-Alexander-200x200.jpg': ['timto', 'tim']
};
// function executed when click to move the image into the other tag
function whenAddImg() {
/* Here you can add a code to be executed when the images is added in the other tag */
return true;
}
/* From here no need to edit */
// create object that will contain functions to alternate image from a tag to another
var obaImg = new Object();
// http://coursesweb.net/javascript/
// put the image in element with ID from "ide"
obaImg.putImg = function(img, ide, stl) {
if(document.getElementById(ide)) {
document.getElementById(ide).innerHTML = '<img src="'+ img+ '" '+stl+' />';
}
}
// empty the element with ID from "elmid", add image in the other element associated to "img"
obaImg.alternateImg = function(elmid) {
var img = obaImg.storeim[elmid];
var addimg = (elmid == obimids[img][0]) ? obimids[img][1] : obimids[img][0];
$('#'+elmid+ ' img').hide(800, function(){
$('#'+elmid).html('');
obaImg.putImg(img, addimg, 'style="display:none;"');
$('#'+addimg+ ' img').fadeIn(500);
});
// function executed after the image is moved into "addimg"
whenAddImg();
}
obaImg.storeim = {}; // store /associate id_elm: image
// add 'image': 'id_elm1', and 'image': 'id_elm1' in "storeim"
// add the image in the first tag associated to image
// register 'onclick' to each element associated with images in "obimids"
obaImg.regOnclick = function() {
for(var im in obimids) {
obaImg.storeim[obimids[im][0]] = im;
obaImg.storeim[obimids[im][2]] = im;
obaImg.putImg(im, obimids[im][0], '');
document.getElementById(obimids[im][0]).onclick = function(){ obaImg.alternateImg(this.id); };
document.getElementById(obimids[im][3]).onclick = function(){ obaImg.alternateImg(this.id); };
}
}
obaImg.regOnclick(); // to execute regOnclick()
FIDDLE
When clicking the items it adds them to a container where I'd like them to be stored if the user navigates to another page. I have seen some local storage cookie code on another script
FIDDLE
var $chks = $('.compare').change(function () {
console.log('c', this)
if ($(this).is(':checked')) {
var img = $('<img>'),
findimg = $(this).closest('.box').find('img'),
data_term = findimg.data('term');
img.attr('src', findimg.attr('src'));
img.attr('data-term', data_term);
var input = '<input type="hidden" name="imagecompare" value="' + data_term + '">';
$('#area').find('div:empty:first').append(img).append(input);
} else {
var term = $(this).data('term'),
findboximage = $('#area > div > img[data-term=' + term + ']')
findboximage.parent('div').empty();
}
localStorage.setItem("imagecookie", $chks.filter(':checked').map(function () {
return $(this).data('term')
}).get().join(','));
});
$(document).on('click', '#area > div', function () {
$(this).empty();
localStorage.clear();
});
var cookie = localStorage.getItem("imagecookie");
if (cookie) {
var terms = cookie.split(',');
if (terms.length) {
$chks.filter($.map(terms, function (val) {
return '[data-term="' + val + '"]'
}).join()).prop('checked', true).change();
}
}
but can't figure how to apply something similar to this one. I would be grateful for any help or to be pointed to some useful places for help.
I was using the following code without Backbone.js and it was working - preventing the ghost images from appearing when trying to drag the image:
$(document).ready(function() {
$('img').attr('draggable', false);
document.getElementsByTagName('img').draggable = false;
});
Now I'm learning backbone.js and trying to implement it in the Views, this is how it looks:
function noDrag () {
$(that.el).find('img').attr('draggable', false);
document.getElementsByTagName('img').draggable = false;
}
noDrag();
It doesn't work.
I know that the key to making this work is getting the part enter code heredocument.getElementsByTagName('img').draggable = false; to work. What's wrong with my code?
Here goes the full code:
window.dolnyPanelView = Backbone.View.extend({
tagName : 'div',
className : 'dolnyPanel-menu-view',
initialize : function() {
var that = this;
// tu wybierz template z templates/main.tpl
this.template = _.template($("#dolnyPanel-view").html());
return this;
},
events : {
},
render : function() {
var that = this;
$(this.el).html(this.template());
$(this.el).find('#panel-view').carousel({
interval: 3000
});
var BandCount;
$.post('api/getBandsCount.php', function(data) {
BandCount=data;
});
var items = getItems(BandCount);
$(this.el).find('.carousel-inner').html($(items));
$(this.el).find('.item').first().addClass('active');
function getItems(BandCount) {
// console.log(BandCount);
var allItems = '';
for (var i = 1; i <= BandCount; i++) {
var items = '';
for (var j = 0; j < 6; j++) {
if (i <= BandCount) {
items += getImageItem(i);
i++;
}
}
allItems += '<div class="item"><div class="row">' + items + '</div></div>';
}
return allItems;
}
function getImageItem(id) {
var item = '<div class="col-md-2 col-sm-3 col-xs-6 artist-col biography-artist-col"><a href="#x" bandId="'+id+'">';
var src = 'LEKSYKON';
$.post('api/getAwatar.php', {id: id}, function(data) {
src = src + data.path;
}, "json");
item += '<img src="' + src + '" alt="Image" class="img-responsive artist"></a></div>';
return item;
}
function noDrag () {
$(that.el).find('img').attr('draggable', false);
document.getElementsByTagName('img').draggable = false;
}
noDrag();
return this;
}
});
UPDATE: thank you for all the answers, it turned out that it's not working because the whole view doesn't work. The thread could be closed now not to mistake anybody.
document.getElementsByTagName returns a NodeList of DOM elements, so you'd need to apply the attribute change to every element rather than to the collection itself.
As you're using jQuery already, you don't need to use document.getElementsByTagName - you can create another jQuery selection.
In fact, that's exactly what you are doing in your first, working example - document.getElementsByTagName is not doing anything there.
You can use jQuery's prop method to reliably change a toggleable attribute for all elements in a selection.
$('img').prop('draggable', false);
See this question for an discussion of prop vs attr.
Try this
//this will get the first img element
var element = document.getElementsByTagName('img')[0];
//setting value of attribute
element.setAttribute("draggable", false);