Can't call jQuery function - javascript

I have a problem with my code.
I want to call a function but it's not working.
First, function show() displays button. This button has id='send' and it's inside the div with class='messagebox'. I want to call function on button click.
(I call function show in php script)
echo<<<ENDL
<div class="friendslistimgbox" onclick="show('$id','$login','$photo')">....</div>
ENDL;
$(.messagebox #send) or $(.messagebox > #send) are not working
$(document).ready(function(){
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
var data = JSON.parse(e.data);
var row = data.from+": "+data.msg+"<br/>";
$("#chats").append(row);
};
$(".messagebox #send").click(function(){
var userId = $("#userId").val();
var msg = $("#msg").val();
var data = {
userId: userId,
msg: msg
};
conn.send(JSON.stringify(data));
})
})
function show(id,login,photo){
$('.messagebox').html("<input type='hidden' id='userId' value='"+login+"'><input type='text' id='msg' class='sendmessage'><button id='send' type='submit' class='button_sendmessage'><i class='icon-right-dir'></i></button>");
$('#message_to').html("<a href='"+login+"'><img src='../userphotos/"+photo+"'>"+login+"</a>");
$("#allmessagesbox").css("visibility","visible");
}
HTML /
<div class="allmessagesbox" id="allmessagesbox">
<div class="messages">
<div class="message_to" id="message_to"></div>
</div>
<div class="messagebox"></div>
</div>
<div id="chats"></div>

You'll need to use the .on() method to register events with DOM elements that are dynamic (ie like your button, which might exist in the future).
In the case of your code, you can use on() in the following way:
// Replace this line:
// $(".messagebox #send").click(function(){
// With this:
$("body").on("click", ".messagebox #send", function(){
var userId = $("#userId").val();
var msg = $("#msg").val();
var data = {
userId: userId,
msg: msg
};
conn.send(JSON.stringify(data));
})
This can basically be read and understood as:
// For any dynamic element in scope or child of the body
$("body")
// Register a click event with any element that matches the
// .messagebox #send selector either now, or in the future
.on("click", ".messagebox #send", function(){
...
}));
For more information on on(), see the jQuery documentation

Related

How can I have 2 separate onmessage event handlers run simultaneously?

I have a webpage with two separate unordered list. After connecting to a websocket, when I send two different messages the live data I get back from the messages only populate the first list, because the onmessage event. I would like data from message 1 to populate list 1 and the data from message 2 to populate list 2 simultaneously.
JavaScript
function sendMessage1(event) {
var input = document.getElementById("messageText1")
ws.send(input.value)
input.value = ''
event.preventDefault()
ws.onmessage = function (event) {
var parsed = JSON.parse(event.data)
var messages = document.getElementById('messages1')
var message = document.createElement('li')
var content = document.createTextNode(JSON.stringify(parsed['data']))
message.appendChild(content)
messages.appendChild(message)
};
}
function sendMessage2(event) {
var input = document.getElementById("messageText2")
ws.send(input.value)
input.value = ''
event.preventDefault()
ws.onmessage = function (event) {
var parsed = JSON.parse(event.data)
var messages = document.getElementById('messages2')
var message = document.createElement('li')
var content = document.createTextNode(JSON.stringify(parsed['data']))
message.appendChild(content)
messages.appendChild(message)
};
HTML
<div class="flex-container">
<div class="flex-child">
<form action="" onsubmit="sendMessage1(event)">
<input type="text" id="messageText1" autocomplete="off" />
<button>Send</button>
</form>
<ul id='messages1'>
<li>Enter Channel Subscription Above</li>
</ul>
</div>
<div class="flex-child">
<form action="" onsubmit="sendMessage2(event)">
<input type="text" id="messageText2" autocomplete="off" />
<button>Send</button>
</form>
<ul id='messages2'>
<li>Enter Channel Subscription Above</li>
</ul>
</div>
</div>
As ultimatum gamer noted, when you do that you overwrite the handler. In order to add several listeners in different places you need some other method:
You can add an event listener
ws.addEventListener('message', event => {
var parsed = JSON.parse(event.data)
var messages = document.getElementById('messages2')
var message = document.createElement('li')
var content = document.createTextNode(JSON.stringify(parsed['data']))
message.appendChild(content)
messages.appendChild(message)
};
// You can add as many as you want!
ws.addEventListener('message', event => {
var parsed = JSON.parse(event.data)
var messages = document.getElementById('messages2')
var message = document.createElement('li')
var content = document.createTextNode(JSON.stringify(parsed['data']))
message.appendChild(content)
messages.appendChild(message)
You can even specify it some potentially useful options
Unrelated to the question, you should wrap the duplicate functionality in its own function, this will save you time: If you change something in one function you need to change it in the other, this will be a headache and a source of annoying bugs.
Also, your code doesn't do what you think it will do, you need to parse it somehow and call the appropiate function. For example:
Create the message: const message = {id: 'messages2', data: input.value}
send message
receive message ws.addEventListener('message', event =>{})
parse message and call appropiate function:
event => {
const parsed = JSON.parse(event.data)
const message = document.createElement('li')
const content = document.createTextNode(JSON.stringify(parsed['data']))
message.appendChild(content)
const messages = document.getElementById(message.id)
messages.appendChild(message)
};
You have to put, the onmessage function, out of the sendMessage function. Because each time you do ws.onmessage = functions () {} you overwrite the function.

Sanitize HTML input using JavaScript server side and client side

I am making an attempt to create my own chatroom using npm, as it stands everything is working smoothly but my main concern is SQL injection or people entering HTML because it will parse anything entered. There is no form being used and the input button, text field and output are all controlled by JavaScript. below is the part of the HTML I am referring to.
<div id="wrapper">
<div class="bubble-container" ></div>
</div>
<div id="sendCtrls">
<input type="text" placeholder="Your message here" id="text">
<button id="myBtn">Send</button>
</div>
This is my .php file which contains all the JavaScript.
<script>
// -------------------------
//var name = prompt('What is your name?');
var name = "<?php echo $_SESSION['username']; ?>";
var bubbles = 1;
var maxBubbles = 60;
var sock = new WebSocket("ws://localhost:5001");
sock.onopen = function() {
var bubble = $("#wrapper");
bubble = $('<div class="bubble-container"><span class="bubble"><div class="bubble-text">\
<p><b>*** Welcome '+name+' to the chat!</b><br>\
These are the rules, please read & follow them.<br>\
1. Be polite in chat.<br>\
2. Keep personal disputes out of chat.<br>\
3. No advertising.<br>\
4. Do not ask to become a Moderator.\
</p></div></div>');
myChat(bubble);
sock.send(JSON.stringify({
type: "name",
data: name
}));
}
// --------------------------
var maxLength = 200; // chars per bubble
sock.onmessage = function(event){
console.log(event);
var json = JSON.parse(event.data);
var bubble = $('<div class="bubble-container"><span class="bubble"><div class="bubble-text"><p><strong>'+json.name+':</strong> '+json.data+'</p></div></div>');
myChat(bubble);
}
// ---------------------------
document.querySelector('button').onclick = function (){
var text = document.getElementById('text').value;
if(text != "") {
if (text.length < maxLength) {
document.getElementById('text').value='';
sock.send(JSON.stringify({
type: "message",
data: text
}));
var bubble = $('<div class="bubble-container"><span class="bubble"><div class="bubble-text"><p><strong>'+name+':</strong> '+text+'</p></div></div>');
myChat(bubble);
}else{
var bubble = $('<div class="bubble-container"><span class="bubble"><div class="bubble-text"><p>*** Your message exceeds '+maxLength+' characters!</p></div></div>');
myChat(bubble);
};
}
};
// --------------------------
var input = document.getElementById("text");
input.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("myBtn").click();
}
});
// --------------------------
function myChat(bubble){
$("#msgText").val("");
$(".bubble-container:last").after(bubble);
if (bubbles >= maxBubbles) {
var first = $(".bubble-container:first").remove();
bubbles--;
}
bubbles++;
$('.bubble-container').show(250, function showNext() {
if (!($(this).is(":visible"))) {
bubbles++;
}
$(this).next(".bubble-container").show(250, showNext);
$("#wrapper").scrollTop(9999999);
});
};
</script>
I have not included the server script which is also just JavaScript but can do so if needed. PHP has no interaction with what is being submitted. 2nd question is, will I need to write anything server side to protect against SQL injection or to prevent HTML being entered?

How do I get an element with a specific ID from getElementsByClassName?

EDIT: SOLVED. Thanks everyone!
I'm new to programming :D My code is below. Here is the deal: I have multiple buttons, but I want to make it so that the same thing would happen anytime any one of these buttons is clicked, but each button also has a specific value, and I also want that specific value to be printed out. My code goes through the document and looks at all the elements with "editButton" class, and correctly identifies all the buttons, but the problem is that no matter which button I press, I always get the value of the last button, because var id only gets assigned after the for loop finishes and is on the last element. I tried creating a global variable and assigning the value to it, but the result is the same. I tried ending the for loop before moving on to .done (function (data), but I got an error. Can someone help me out? Thanks!
$(document).ready(function() {
var anchors = document.getElementsByClassName('editButton');
for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
anchor.onclick = function() {
$.ajax({
method: "GET",
url: "/testedit.php",
}).done(function(data) {
var id = anchor.value;
/* from result create a string of data and append to the div */
var result = data;
var string = '<p>ID is ' + id + '</p><br>';
$("#records").html(string);
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="records"></div>
Actually, instead of doing a huge for loop to add onclick events to your buttons, one of the best ways to do this is to listen to each button with editButton class on click() event then use $(this) which refers to the exact clicked button. After that, you can use each individual button to do whatever you want.
So your final code should be something like this:
$(document).ready(function() {
$('.editButton').click(function() {
console.log('innerHTML is:', $(this).html())
console.log('id is:', $(this).attr('id'))
$.ajax({
method: "GET",
url: "/testedit.php",
}).done(function(data) {
var id = $(this).value;
/* from result create a string of data and append to the div */
var result = data;
var string = '<p>ID is ' + id + '</p><br>';
$("#records").html(string);
});
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="records">
<button class="editButton" id="firstButton">button 1</button>
<button class="editButton" id="secondButton">button 2</button>
<button class="editButton" id="thirdButton">button 3</button>
<button class="editButton" id="fourthButton">button 4</button>
</div>
save the button with button = this when run the onclick function and use it
$(document).ready(function(){
var anchors = document.getElementsByClassName('editButton');
for(var i = 0; i < anchors.length; i++) {
var button;
var anchor = anchors[i];
anchor.onclick = function() {
button = this;
$.ajax({
method: "GET",
url: "/testedit.php",
}).done(function( data ) {
/* from result create a string of data and append to the div */
var result= data;
var string='<p>ID is '+ button.value +'</p><br>';
$("#records").html(string);
});
}
}
});
https://jsfiddle.net/x02srmg6/
You need to look in to JavaScript closures and how they work to solve this.
When you add event listeners inside a for loop you need to be careful in JS. When you click the button, for loop is already executed and you will have only the last i value on every button press. You can use IIFE pattern, let keyword to solve this.
One simple way to resolve this issue is listed below.
<div id="records"></div>
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var anchors = document.getElementsByClassName('editButton');
for(var i = 0; i < anchors.length; i++) {
//Wrap the function with an IIFE and send i value to the event listener
(function(anchor){
anchor.onclick = function() {
$.ajax({
method: "GET",
url: "/testedit.php",
}).done(function( data ) {
var id = anchor.value;
/* from result create a string of data and append to the div */
var result= data;
var string='<p>ID is '+id+'</p><br>';
$("#records").html(string);
});
}
})(anchors[i]);
}
}
});
You can read more about this in JavaScript closure inside loops – simple practical example
In your code..
var id = anchor.value;
could be
var id = anchor.id;
but I recommend you to use event delegation
If you have a html like this
<div id="buttonArea">
<a class="editButton" id="1"/>
<a class="editButton" id="2"/>
<a class="editButton" id="3"/>
.......(so many buttons)
</div>
you can code like below.
$(document).ready(function(){
$('#buttonArea').on('click', 'a.editButton', function (event) {
var anchor = event.currentTarget;
$.ajax({
method: "GET",
url: "/testedit.php",
})
.done(function(data) {
var id = anchor.id;
/* from result create a string of data and append to the div */
var result= data;
var string='<p>ID is '+id+'</p><br>';
$("#records").html(string);
});
}
You can use getAttribute. Like:
var anchors = document.getElementsByClassName('editButton');
// Id of anchors
id_of_anchor = anchors.getAttribute("id");
Refs
EDIT
anchor.onclick = function() {
id_of_anchor = $(this).attr("id");
});
You have jQuery in your application, there is easier and more readable way to do it with jQuery;
$(document).ready(function() {
$(".editButton").each(function(a, b) {
$('#' + $(b).attr('id')).on('click', function() {
$.ajax({
method: "GET",
url: "/testedit.php",
}).done(function(data) {
var id = $(b).attr('id');
/* from result create a string of data and append to the div */
var result = data;
var string = '<p>ID is ' + id + '</p><br>';
$("#records").html(string);
});
});
});
});
Example: https://jsfiddle.net/wao5kbLn/

How can I use an autosave partial view on a page with multiple forms?

Extending the example found at Autosave in MVC (ASP.NET), I wanted to create a partial to reuse in my application. I have one view with a tabbed layout, and each tab has its own form, and this is causing problems, namely that every form tries to submit every time, and only the first timestamp in the document updates. I understand why this is happening, but I don't know how I can fix it.
Partial's cshtml:
<div class="form-group">
<label class="control-label col-lg-2" for=""> </label>
<div class="col-lg-10">
<span class="help-block" id="autosaveTime">Not Autosaved</span>
</div>
</div>
#{
var autosaveString = "'" + #ViewData["autosaveController"] + "'";
if (ViewData["autosaveAction"] != null && ViewData["autosaveAction"] != "")
autosaveString += ", '" + ViewData["autosaveAction"] + "'";
}
<script type="text/javascript">
$(document).ready(function () {
autosave(#Html.Raw(autosaveString));
});
</script>
Javascript:
//methodName is optional-- will default to 'autosave'
function autosave(controllerName, methodName)
{
methodName = typeof methodName !== 'undefined' ? methodName : 'autosave'
var dirty = false;
$('input, textarea, select').keypress(function () {
dirty = true;
});
$('input, textarea, select').change(function () {
dirty = true;
});
window.setInterval(function () {
if (dirty == true) {
var form = $('form');
var data = form.serialize();
$.post('/' + controllerName + '/' + methodName, data, function () {
$('#autosaveTime').text("Autosaved at " + new Date);
})
.fail(function () {
$('#autosaveTime').text("There was a problem autosaving, check your internet connection and login status.");
});
dirty = false;
}
}, 30000); // 30 seconds
}
I have 2 ideas on how to fix it, but not sure which is more maintainable/workable:
Give each form an id, and pass that to the partial/autosave function. Add the name to the autosavetime text block for updates, and to determine which form to serialize/submit.
Somehow use jquery's closest function to find the form where the autosave block was placed, and use that to do what I was doing explicitly with #1.
First, make the URL using your Razor helper's Html extension (dynamically piecing URLs like this in JavaScript is unnecessarily risky). Take that, and stuff it in a data attribute on the tab control like so:
<div class="tab autosave" data-action-url='#Html.Action("Action", "Controller")'>
<form>
<!-- Insert content here -->
</form>
</div>
Then, you'll want something like this ONCE -- do not include it everywhere, and remove the javascript from your partial completely:
$(function() {
// Execute this only once, or you'll end up with multiple handlers... not good
$('.autosave').each(function() {
var $this = $(this),
$form = $this.find('form'),
dirty = false;
// Attach event handler to the tab, NOT the elements--more efficient, and it's always properly scoped
$this.on('change', 'input select textarea', function() {
dirty = true;
});
setInterval(function() {
if(dirty) {
// If your form is unobtrusive, you might be able to do something like: $form.trigger('submit'); instead of this ajax
$.ajax({
url : $this.data('action-url'),
data : $form.serialize()
}).success(function() {
alert("I'm awesome");
dirty = false;
});
}
}, 30 * 1000);
});
});

How can I delete the selected messages (with checkboxes) in jQuery?

I'm making a messaging system and it has a lot of AJAX. I'm trying to add a bulk actions feature with check boxes. I've added the checkboxes, but my problem is that I don't know how to make something happen to the selected messages.
Here's my function that happens whenever a checkbox is clicked:
function checkIt(id) {
if ($('#checkbox_' + id).is(':checked')) {
$('#' + id).addClass("selected");
}
else {
$('#' + id).removeClass("selected");
}
}
But, I don't know where to go from there.
Here is some example markup for one of the lines [generated by PHP] of the list of messages:
<div class="line" id="33" >
<span class="inbox_check_holder">
<input type="checkbox" name="checkbox_33" onclick="checkIt(33)" id="checkbox_33" class="inbox_check" />
<span class="star_clicker" id="star_33" onclick="addStar(33)" title="Not starred">
<img id="starimg_33" class="not_starred" src="images/blank.gif">
</span>
</span>
<div class="line_inner" style="display: inline-block;" onclick="readMessage(33, 'Test')">
<span class="inbox_from">Nathan</span>
<span class="inbox_subject" id="subject_33">Test</span>
<span class="inbox_time" id="time_33" title="">[Time sent]</span>
</div>
</div>
As you can see, each line has the id attribute set to the actual message ID.
In my function above you can see how I check it. But, now what I need to do is when the "Delete" button is clicked, send an AJAX request to delete all of the selected messages.
Here is what I currently have for the delete button:
$('#delete').click(function() {
if($('.inbox_check').is(':checked')) {
}
else {
alertBox('No messages selected.'); //this is a custom function
}
});
I will also be making bulk Mark as Read, Mark as Unread, Remove Star, and Add Star buttons so once I know how to make this bulk Delete work, I can use that same method to do these other things.
And for the PHP part, how would I delete all them that get sent in the AJAX request with a mysql_query? I know it would have to have something to do with an array, but I just don't know the code to do this.
Thanks in advance!
How about this
$('#delete').click(function() {
var checked = $('.inbox_check:checked');
var ids = checked.map(function() {
return this.value; // why not store the message id in the value?
}).get().join(",");
if (ids) {
$.post(deleteUrl, {idsToDelete:ids}, function() {
checked.closest(".line").remove();
});
}
else {
alertBox('No messages selected.'); // this is a custom function
}
});
Edit: Just as a side comment, you don't need to be generating those incremental ids. You can eliminate a lot of that string parsing and leverage jQuery instead. First, store the message id in the value of the checkbox. Then, in any click handler for a given line:
var line = $(this).closest(".line"); // the current line
var isSelected = line.has(":checked"); // true if the checkbox is checked
var msgId = line.find(":checkbox").val(); // the message id
var starImg = line.find(".star_clicker img"); // the star image
Assuming each checkbox has a parent div or td:
function removeDatabaseEntry(reference_id)
{
var result = null;
var scriptUrl = './databaseDelete.php';
$.ajax({
url: scriptUrl,
type: 'post',
async: false,
data: {id: reference_id},
success: function(response)
{
result = response;
}
)};
return result;
}
$('.inbox_check').each(function(){
if ($(this).is(':checked')){
var row = $(this).parent().parent();
var id = row.attr('id');
if (id == null)
{
alert('My selector needs updating');
return false;
}
var debug = 'Deleting ' + id + ' now...';
if (console) console.log(debug);
else alert(debug);
row.remove();
var response = removeDatabaseEntry(id);
// Tell the user something happened
$('#response_div').html(response);
}
});

Categories

Resources