I'm pretty new to Jquery and javaScript, and I am trying to do the following:
I have a text field in a table. I want to be able to change it to a input field, and when the user clicks a button, save it in the db (by using a Ajax call) and change it back to text again.
I've been able to do exactly that, but the strange thing is that it only works once, after saving, you can not edit the same field again, unless I refresh the page.
The HTML is:
<table class="table table-bordered">
<tr>
<td>My data field :</td>
<td id="MyDataField">123 <i class="fa fa-pencil-square-o fa-fw" id="editMyDataField" style='float: right' /></td>
</tr>
</table>
The javascript is:
$('#editMyDataField').on('click', function() {
//First clikck, change the table cell into a input field, with the current text value and change icon
$('td#MyDataField').html($('<input />', {
'value': $('td#MyDataField').text()
}));
$('td#MyDataField').append('<i class="fa fa-check" id="editMyDataField" style="float: right"/>')
//Second click, do something with the vale (for instance Ajax call), change field back to text with the new value, and change icon
$('#editMyDataField').on('click', function() {
alert("Save value in db: " + $('td#MyDataField input').val())
$('td#MyDataField').html($('td#MyDataField input').val() + '<i class="fa fa-pencil-square-o fa-fw" id="editMyDataField" style="float: right"> ');
})
})
I've created a JSfiddle to demonstrate the problem: https://jsfiddle.net/2zkbvhoL/
I have a hunch that by repacing the icon, I'm somehow "losing" the connection to the click function, but am not sure how I should solve it.
I think changing the structure would be a better solution.
Instead of: 123 <i class="fa fa-pencil-square-o fa-fw" id="editMyDataField" style='float: right' />
Why not: <span class="text">123</span><input class="edit" type="text"><button type="button"><i ...></i></button>?
$(function(){
$(".edit-btn").click(function(){
var $field = $(this).closest(".field");
if (!$field.data("editing")) {
$field.data("editing", true);
$field.find(".edit-input").val($field.find(".text").text()).show();
$field.find(".edit-btn").hide();
$field.find(".ok-btn").show();
$field.find(".text").hide();
}
})
$(".ok-btn").click(function(){
var $field = $(this).closest(".field");
if ($field.data("editing")) {
$field.find(".edit-input").attr("disabled", true);
runAjax($field, function(){
$field.find(".edit-input").attr("disabled", false);
$field.data("editing", false);
$field.find(".edit-input").hide();
$field.find(".edit-btn").show();
$field.find(".ok-btn").hide();
$field.find(".text").show();
});
}
})
function runAjax($field, cb) {
//your ajax here. Below is just a delay for demoing
setTimeout(function(){
//If ajax OK, you would want to change the text to the input's value
$field.find(".text").text($field.find(".edit-input").val());
if (typeof cb === "function")
cb();
}, 1000);
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div data-editing="false" class="field">
<span class="text">123</span>
<input class="edit-input" type="text" style="display:none">
<button type="button" class="edit-btn">Edit</button>
<button type="button" class="ok-btn" style="display:none">OK</button>
</div>
UPDATE:
See demo here
https://jsfiddle.net/2zkbvhoL/7/
Try using
$('table').on('click','#editMyDataField', function() {
// your code here...
}))
Instead of table you can also use document as well and change it at both the places.
So this code should work for you:
$('table').on('click','#editMyDataField', function() {
//First clikck, change the table cell into a input field, with the current text value and change icon
$('td#MyDataField').html($('<input />', {
'value': $('td#MyDataField').text()
}));
$('td#MyDataField').append('<i class="fa fa-check" id="saveMyDataField" style="float: right"/>')
//Second click, do something with the vale (for instance Ajax call), change field back to text with the new value, and change icon
$('table').on('click','#saveMyDataField', function() {
alert("Save value in db: " + $('td#MyDataField input').val())
$('td#MyDataField').html($('td#MyDataField input').val() + '<i class="fa fa-pencil-square-o fa-fw" id="editMyDataField" style="float: right"> ');
})
});
Changed editMyDataField to be saveMyDataField on the inside of the function.
Although this is just a quick fix to your solution. You can remove the nested event binding and attach the events separately to the both the buttons(the edit and save icons)
Related
I am working on edit username with hide/show text field and, I found some questions for 'js works in console but not in code' but I have different scenario. some part jquery run perfectly, but rest of code is not working in code, it works in console, please help me with that. (I have loaded jquery that's why some code works)
on edit click
Here are the images for buttons
fisrt for edit name
second for close edit button which is not working
//for edit field showing
$(document).on('click', '.edit-nickname', (element) => {
element.preventDefault();
$('.hide-on-cancel').show();
$('.show-on-cancel').hide();
});
//for hiding edit field and display username
$(document).on('click', '.cancel-nickname', (element) => {
element.preventDefault();
// alert('hii');
$('.hide-on-cancel').hide();
$('.show-on-cancel').show();
//(OPTIONAL CODE to ABOVE) IF I UNCOMMENT BELOW 3 LINE THAT WORKS BUT 4th and 5th LINE IS NOT WORKING
// $('#sd-close').addClass('d-none');
// $('#sd-check').addClass('d-none');
// $('#sd-edit').addClass('d-none');
// $('#sd-pen').removeAttr('style');
// $('#text-edit-nickname').removeAttr('style');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="edit-nickname" class="second-text1">
<div class="row" style="padding-left: 50px;width: 90%;margin: auto;">
<span class="show-on-cancel" id="text-edit-nickname" data-toggle="tooltip" data-placement="top" title="{{ \Auth::user()->nickname}}">
{{ucfirst(\Auth::user()->nickname)}}
</span>
<span class="form-group nickname-form-group cust-d-none hide-on-cancel" id="sd-edit">
<input id="new_nickname" class="form-control" style="height: 44px;margin-top: 20px;" name="nickname" type="text" value="{{ \Auth::user()->nickname}}" >
<input id="old_nickname" class="" type="hidden" value="{{ \Auth::user()->nickname}}" >
</span>
<span class="edit-nickname">
<i class="fa fa-pencil ml-4 show-on-cancel" id="sd-pen"></i>
<i class="fa fa-check ml-2 save-nickname cust-d-none hide-on-cancel" id="sd-check"></i>
<i class="fa fa-times cust-d-none cancel-nickname hide-on-cancel" id="sd-close"></i>
</span>
</div>
</div>
First put your script tag at the end of your body tag.
Then add document.ready function to your code like below:
$(document).ready(function(){
$(document).on('click', '.edit-nickname', (element) => {
element.preventDefault();
$('.hide-on-cancel').show();
$('.show-on-cancel').hide();
});
//for hiding edit field and display username
$(document).on('click', '.cancel-nickname', (element) =>{
element.preventDefault();
// alert('hii');
$('.hide-on-cancel').hide();
$('.show-on-cancel').show();
//(OPTIONAL CODE to ABOVE) IF I UNCOMMENT BELOW 3 LINE THAT WORKS BUT 4th and 5th LINE IS NOT WORKING
// $('#sd-close').addClass('d-none');
// $('#sd-check').addClass('d-none');
// $('#sd-edit').addClass('d-none');
// $('#sd-pen').removeAttr('style');
// $('#text-edit-nickname').removeAttr('style');
});
});
In a nodejs application previously it was using custom js confirms, so I have removed that and applied confirms using Bootblox.js.
After pressing the delete post button it will ask for confirm and after the confirmation it does not remove the post...rather after pressing the delete button again it removes it from the page....
Previous code using custom JS confirms is-
<form method="POST" action="/delete/<%= one._id %>?_method=DELETE" style="display: inline;">
<button class="btn btn-sm btn-danger delete-button"
style="color: white;"
href="/delete/<%= one._id %>"
onclick="return confirm('Are you sure you want to delete this?')">
<i class="fas fa-trash"></i>
</button>
</form>
code which I replaced in place of above using bootblox.js-
In Html tag-
<form method="POST" action="/delete/<%= one._id %>?_method=DELETE" style="display: inline;">
<button class="btn btn-sm btn-danger delete-button"
style="color: white;"
href="/delete/<%= one._id %>"
type="button"
onclick="return askConfirm(' Warning! ','Are you sure you want to delete this?')">
<i class="fas fa-trash"></i>
</button>
</form>
In the srcipt tag-
var confirmVariable = false;
function askConfirm(title,message){
bootbox.confirm({
title: title,
message: message,
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: function (result) {
if(result){
confirmVariable=true;
} else {
confirmVariable=false;
}
}
});
if(confirmVariable==true){
return true;
}else{
return false;
}
}
As in custom/default JS confirms it returns a 'true' or 'false' on selection of 'OK' or 'Cancel', the confirms using another js library doesnt, so here i have made a function 'askConfirm()', which is defined in script tag. In this function it will open the confirm window and open selcting OK or Cancel it will set the variable 'confirmVariable==true' or 'confirmVariable==false' and will return to the 'onclick' on the html tag. So as like the default confirms it was expected to submit the delete form in one go and delete it from the page.
But the problem is that when i press delete button confirm window appears and upon selecting Ok it doesn't deletes the post...rather when i click delete button again after this it deletes it.
I want to make it delete in one go. How can it be made?
Please help! Thanks in Advance!
You have an issue where you check for if(confirmVariable==true) before its been set. Its a typical async issue where you check for something before the action has been completed.
Where you wait for the user to click confirm/cancel, the position you set the variable is in a callback, so will only change when the user clicks a button. You immediately check for a result before the user clicks, which I assume is false at first. Then the user clicks and the value changed. Now the second time the user clicks, you immediately check what they clicked and you, by accident, look at the button they clicked the first time.
So when you provide the popup to the user with this, rather do your action inside the callback
bootbox.confirm({
title: title,
message: message,
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: function (result) {
if(result)
doThis(true)
else
doThis(false)
}
});
function doThis(confirmed){
if (confirmed)
console.log('user clicked confirm')
else
console.log('user clicked cancel')
}
If you want style points you can simply do this
bootbox.confirm({
title: title,
message: message,
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: doThis
});
function doThis(confirmed){
if (confirmed)
console.log('user clicked confirm')
else
console.log('user clicked cancel')
}
when user click for a second time click do not work, user need to reload the page again to it works
<script>
$(document).ready(function() {
$("#like_post").click(function(e) {
// $("#like_post").on("click", "#like_post", function (e) {
e.preventDefault();
var post_info = $("#post_info :input").serialize();
$.post("backend/ajax/like_post.php", post_info).done(function(data) {
$("#like_post").html(data);
$("#like").load(location.href+" #like>*","");
}).fail(function() {
//alert("Error submitting forms!");
})
})
})
</script>
this is the backend return from db
if user liked it will show
<div id="like_post><a href="" id="l"><input type="hidden" value="unlike" name="like_button" /><i style="color:red" class="fa fa-heart fa-2x" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="'.$lang['you_liked_it'].'"></i>
</a></div>
else it will show
<div id="like_post"> <a href="" id="l"><input type="hidden" value="like" name="like_button" /><i class="fa fa-heart-o fa-2x" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="'.$lang['like_it'].'"></i>
</a></div>
the same validation is on frontend where is will change the hidden input to like, or unlike , my backend check is fine and returning all ok when I check the html response, but the problem is that jquery do not work when user like and unlike without reload the page, it just get the first click and after that user need to reload the page to it works.
I had a similar issue before and it was something with event delegation.
Use the comment line in your code without "#like_post":
$("#like_post").on("click", function (e) {
});
I have this situation:
<a href="#"
class="btn btn-xs btn-bricky tooltips"
:data-id="row.id"
data-placement="top"
data-original-title="Remove"
#click.self.stop="removeRow($event)">
<i class="fa fa-times fa fa-white"></i>
</a>
Now, when I click on link it's ok, but if I click on <i> (which is inside of <a>) nothing happens (because of #click.self.stop).
What I would like to achieve is to trigger same method, in this case removeRow(), no matter if I click <a> or <i> is clicked. I need to get data-id attribute form ahref.
What I would like to achieve is to trigger same method, in this case removeRaw, no matter if I click <a> or <i> is clicked.
From what you say, you actually have to just remove the .self modifier.
Per docs (Event Handling/Event Modifiers/.self):
<!-- only trigger handler if event.target is the element itself -->
<!-- i.e. not from a child element -->
<div v-on:click.self="doThat">...</div>
See changed code below.
new Vue({
el: '#app',
data: {
rows: [{id: 1, name: "row1"}, {id: 2, name: "row2"}]
},
methods: {
removeRow($event) {
console.log($event.currentTarget.dataset.id)
}
}
})
<script src="https://unpkg.com/vue#2.5.13/dist/vue.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<div id="app">
<div v-for="row in rows">
<a href="#"
class="btn btn-xs btn-bricky tooltips"
:data-id="row.id"
data-placement="top"
data-original-title="Remove"
#click.stop="removeRow($event)">
<i class="fa fa-times fa fa-white"></i> {{ row.name }}
</a>
</div>
</div>
The only modified bit in the template was #click.self.stop="removeRow($event)"
to #click.stop="removeRow($event)".
In the JS part, I created a rows just to test, and added console.log($event.currentTarget.dataset.id) to show how to get the id.
Then you don't need to use stop propagation or call function on self:
<a href="#"
class="btn btn-xs btn-bricky tooltips"
:data-id="row.id"
data-placement="top"
data-original-title="Remove"
#click.prevent="removeRow($event)">
<i class="fa fa-times fa fa-white"></i>
</a>
prevent is used to prevent the default link action.
You can use currentTarget instead of target to identify the attached element and get the href value from there.
$event.currentTarget.href
Alternatively, why not just to set the value in params:
#click.prevent="removeRow('your-value')"
In your method:
removeRow(myvalue) {
// do whatever you want to do with myvalue
}
The solution is quite easy. use #click.stop
#click.stop(openUser(user))
You can use the following sample to get it to work.
Run the code and click on the three texts, but you will only get the data-id value of the child and parent divs
new Vue({
el: '#app',
methods: {
init($event){
let el = $event.target.nodeName
var id = null;
if(el == 'A'){
id = $event.target.dataset.id
}
if(el == 'I'){
id = $event.target.parentElement.dataset.id
}
console.log( ' id', id)
}
}
})
<script src="https://unpkg.com/vue#2.5.9/dist/vue.js"></script>
<div id="app">
<a href="#" #click='init' data-id='42'> Inside A <br/>
<i>Inside I</i>
</a>
</div>
Font awesome is not working for me when I try to change the value of an element using a javascript.
Javascript:
function onClick() {
document.getElementById("dicebutton").value='Rolling <i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>';
}
HTML code for button:
<form>
Bet<br>
<input type="text" name="bet"><br>
Chance<br>
<input type="text" name="chance"><br>
<h3>Payout: 0.0000BTC</h3>
<input value = "Roll dice" id="dicebutton" onClick="onClick()" type="button" style="vertical-align:middle"></input>
</form>
Result:
Notice how the green button spits raw HTML while the top of the website correctly displays the fonts? How can I fix this?
Use the element.innerHTML = content; syntax if you want to add HTML. ".value" only passes data as a string.
So
document.getElementById("dicebutton").innerHTML='Rolling <i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>';
Edit:
I just realized you are using an < input > field for your button. This wont work in that case. The only value for an < input > field that you can use to change the button text is value= as you tried. Unfortunately "value" treats anything assigned to it as a string.
Instead of an < input > field, you will need to use an element that you can attach HTML to - for example, an < a > tag, a < button > tag, or simply using a styled div as a button. This will allow you to pass the HTML to it without having to use "value".
Use a <button> tag instead of <input> and change
document.getElementById("dicebutton").value
to
document.getElementById("dicebutton").innerHTML
You must use button instead of input button, then update the content with innerHTML.
Example:
Javascript:
function onClick() {
// you can you "this.innerHTML" too
document.getElementById("dicebutton").innerHTML='Rolling <i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>';
}
HTML:
<button id="dicebutton" onclick="onClick()" style="vertical-align:middle">Roll dice</button>