Editable multiple forms on a table - javascript

I am using editable plugin to preform in place edit
This is the code I am using that I got from their Doc page, it is supposed to be used for adding new records, But I want to use it to modify records)
<script>
$(document).ready(function() {
//init editables
$('.myeditable').editable({
url: '/post',
placement: 'right'
});
//make username required
$('#new_username').editable();
//automatically show next editable
$('.myeditable').on('save.newuser', function(){
var that = this;
setTimeout(function() {
$(that).closest('td').next().find('.myeditable').editable('show');
}, 500);
});
//create new user
$('#save-btn').click(function() {
$('.myeditable').editable('submit', {
url: '/newuser',
ajaxOptions: {
dataType: 'json' //assuming json response
},
success: function(data, config) {
if(data && data.id) { //record created, response like {"id": 2}
//set pk
$(this).editable('option', 'pk', data.id);
//remove unsaved class
$(this).removeClass('editable-unsaved');
//show messages
var msg = 'New user created! Now editables submit individually.';
$('#msg').addClass('alert-success').removeClass('alert-error').html(msg).show();
$('#save-btn').hide();
$(this).off('save.newuser');
} else if(data && data.errors){
//server-side validation error, response like {"errors": {"username": "username already exist"} }
config.error.call(this, data.errors);
}
},
error: function(errors) {
var msg = '';
if(errors && errors.responseText) { //ajax error, errors = xhr object
msg = errors.responseText;
} else { //validation error (client-side or server-side)
$.each(errors, function(k, v) { msg += k+": "+v+"<br>"; });
}
$('#msg').removeClass('alert-success').addClass('alert-error').html(msg).show();
}
});
});
//reset
$('#reset-btn').click(function() {
$('.myeditable').editable('setValue', null)
.editable('option', 'pk', null)
.removeClass('editable-unsaved');
$('#save-btn').show();
$('#msg').hide();
});
});
</script>
And this is the html
<tr>
<td>adel</td>
<td></td>
<td></td>
<td></td>
<td><img src=""></img></td>
<td width="10%"><button id="save-btn" class="btn btn-primary btn-sm">Ok</button><button id="reset-btn" class="btn btn-sm pull-right">Reset</button></td>
</tr>
<tr>
<td>sdqsd</td>
<td></td>
<td></td>
<td></td>
<td><img src=""></img></td>
<td width="10%"><button id="save-btn" class="btn btn-primary btn-sm">Ok</button><button id="reset-btn" class="btn btn-sm pull-right">Reset</button></td>
</tr>
<tr>
<td>dzadz</td>
<td>from me with love</td>
<td>anywhere</td>
<td>http://justawebsite.com</td>
<td><img src=""></img></td>
<td width="10%"><button id="save-btn" class="btn btn-primary btn-sm">Ok</button><button id="reset-btn" class="btn btn-sm pull-right">Reset</button></td>
</tr>
Now everything works fine, Except if I edit one of the 2 first rows and hit Ok It will send the details of the last form http://justawebsite.com and sometimes it doesn't send anything, It is really messed up and I spent hours reading te documentation but I couldn't figure out the problem

As I said in my comment, you've got different elements with the same id, so the selectors won't work (id must be unique). Put them as class instead:
<tr>
<td>
adel
</td>
<td>
</td>
<td>
</td>
<td>
</td>
<td>
<a href="#" class="myeditable picture" data-type="text" data-name="picture" data-original-title="Enter Picture">
<img src="" />
</a>
</td>
<td width="10%">
<button class="btn btn-primary btn-sm save-btn">Ok</button>
<button class="btn btn-sm pull-right reset-btn">Reset</button>
</td>
</tr>
Here's a fiddle to get you started https://jsfiddle.net/virginieLGB/k2of9xor/1/
On there, you'll see that I've selected the editable elements you want to submit.
$('.save-btn').click(function() {
var that = $(this);
var allEditables = that.parents("tr").find(".myeditable"); // all ".myeditable" elements in the same "tr" as the ".save-btn" that was clicked on
allEditables.each(function() {
// here I've kept your code because I don't know what happens in your file, but maybe you need a bulk action
$(this).editable('submit', {
...
I don't know how your PHP file works, so don't know how you save your user and if you need to submit all fields at once or not. If so, you'll have to modify my answer a bit.

Have you tried refreshing it afterwards?
For me i noticed, that as soon as it was refreshed i got the result that i have been expecting, but only for one of them. However, i couldn't solve the problem yet.
Please let me know what kind of result you get.
Otherwise try debugging...disable one of the first rows and try it again..

Related

AngularJS: new object not showing in table

I am using dir-paginate library to paginate my data on the page. The issue I am having is when I am adding a new object to the list and viewing this on the page instantly. On the controller side every thing seems to work just alright.
Here is my controller
/**
* Array of all the items
*/
$scope.allItems = [];
$scope.postResource = function() {
ProjectsFactory.save($scope.newProject)
.success(function(data) {
$scope.allItems.push(data);
console.log($scope.allItems);
$scope.newProject = ''
ToastService.show('Added successfully!');
})
.error(function(data) {
sweetAlert("Oops...", "Something went wrong!", "error");
console.log(data);
});
}
Notice the log I am doing right there. On the console page I can see the new object is being added to the rest of the objects. I believe the issue is occurring on the view side which looks just like this.
<table class="table table-bordered table-hover table-condensed bg-white" st-table="rowCollectionBasic">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="item in allItems | filter: search.query | itemsPerPage : itemPerPage" total-items="totalProjects" current-page="currentPage">
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td style="width:150px">
<button class="btn btn-info btn-sm" ng-click="showEditDialog($event, item)">
<i class="glyphicon glyphicon-edit"></i>
</button>
<button class="btn btn-danger btn-sm" ng-click="deleteResource(item, $index)">
<i class="glyphicon glyphicon-trash"></i>
</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="20" class="text-center">
<dir-pagination-controls on-page-change="pageChanged(newPageNumber)" boundary-links="true"></dir-pagination-controls>
<md-progress-circular md-mode="indeterminate" ng-if="AjaxInProgress"></md-progress-circular>
</td>
</tr>
</tfoot>
To see the new created object on the page, I need to either refresh the page or click somewhere else and return to the same page again.
Someone has an idea what I am doing wrong?
Update #1
The project service has $http
// save a new resource
save: function(data) {
return $http({
url: $rootScope.baseUrl + 'projects',
method: 'POST',
data: data
});
},
Thanks!

Getting Error: [ngRepeat:dupes] in ng-repeat using angular.js

I am getting the following error while i have no data using ng-repeat in Angular.js
Error:
Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.6/ngRepeat/dupes?p0=user%20in%20objHodUserData&p1=string%3Al&p2=l
at Error (native)
at http://oditek.in/Gofasto/js/angularjs.js:6:416
at http://oditek.in/Gofasto/js/angularjs.js:279:39
at Object.fn (http://oditek.in/Gofasto/js/angularjs.js:129:128)
at n.$digest (http://oditek.in/Gofasto/js/angularjs.js:130:206)
at n.$apply (http://oditek.in/Gofasto/js/angularjs.js:133:236)
at g (http://oditek.in/Gofasto/js/angularjs.js:87:376)
at K (http://oditek.in/Gofasto/js/angularjs.js:91:448)
at XMLHttpRequest.z.onload (http://oditek.in/Gofasto/js/angularjs.js:92:462)
I am explaining my code below.
<tbody id="detailsstockid">
<tr ng-repeat="user in objHodUserData ">
<td>{{$index+1}}</td>
<td>{{user.user_name}}</td>
<td>{{user.email}}</td>
<td>{{user.mob_no}}</td>
<td>{{user.login_name}}</td>
<td ng-if="user.user_status==1">Enable</td>
<td ng-if="user.user_status==0">Disable</td>
<td>
<a ui-sref='hod.user'>
<input type='button' class='btn btn-xs btn-green' value='Edit' ng-click="editUserData(user.user_id)" >
</a>
</td>
<td>
<a ui-sref='hod.user'>
<input type='button' class='btn btn-xs btn-red' value='Delete' ng-click="deleteUserData(user.user_id);" >
</a>
</td>
</tr>
</tbody>
When the object objHodUserData has no data these type error is coming.I tried to resolve this by using track by $index. By using this error has gone but 4 blank rows are generating.Here i need when there is no data present no rows will generate without any error and when data will be there it will display.Please help me to resolve this error.
I had the same problem, and I solved it by wrapping all the <tbody> within a <div> element.
and inserting ng-show in this div element like that
<div ng-show="hasElements()">
and in your controller you have a $scope function to check if there is elements in the object like that:
$scope.hasElements = function(){
return objHodUserData.length ===0;
}
and that should work.
let me if it solved your problem.
Cheers.
Try using ng-if along with ng-repeat.It should be ng-if="objHodUserData.length !=0"
If you don't mind using lodash, then this is a handy utility library for your javascript, which can help with tasks like this.
var objHodUserDataWithoutBlanks = _.filter(objHodUserData, function(n) {
return n.user_name != "";
});
The above will filter out entries that have a blank username. Then your ng-repeat can instead repeat over this object without blanks: objHodUserDataWithoutBlanks.
Edit: Alternate method using only angularjs:
Add an angular filter:
myApp.filter('nonBlankOnly', function() {
return function( items) {
var filtered = [];
angular.forEach(items, function(item) {
if(item.user_name != "") {
filtered.push(item);
}
});
return filtered;
};
});
Then apply the filter in your controller:
function myCtrl($scope, $filter)
{
$scope.objHodUserDataWithoutBlanks = $filter('nonBlankOnly')(objHodUserData);
}
And repeat through filtered items:
<tr ng-repeat="user in objHodUserDataWithoutBlanks">
Maybe you can use de ng-show to check if there is an existing user, something like:
<tr ng-repeat="user in objHodUserData ">
<td ng-show="user">{{$index+1}}</td>
<td ng-show="user">{{user.user_name}}</td>
<td ng-show="user">{{user.email}}</td>
<td ng-show="user">{{user.mob_no}}</td>
<td ng-show="user">{{user.login_name}}</td>
or if you prefer to hide the entire row, put the ng-show on the <tr> element.
<tbody id="detailsstockid">
<tr ng-repeat="user in objHodUserData " ng-show="user">
<td>{{$index+1}}</td>
<td>{{user.user_name}}</td>
<td>{{user.email}}</td>
<td>{{user.mob_no}}</td>
<td>{{user.login_name}}</td>
<td ng-if="user.user_status==1">Enable</td>
<td ng-if="user.user_status==0">Disable</td>
<td>
<a ui-sref='hod.user'>
<input type='button' class='btn btn-xs btn-green' value='Edit' ng-click="editUserData(user.user_id)" >
</a>
</td>
<td>
<a ui-sref='hod.user'>
<input type='button' class='btn btn-xs btn-red' value='Delete' ng-click="deleteUserData(user.user_id);" >
</a>
</td>
</tr>
</tbody>

How identify a secondary Id of a html element with multiple IDs

In my project, one of the jsp pages have this html structure:
<table id="hor-minimalist-a" class="campos">
<thead>
<tr>
<th>Campo</th>
<th>#</th>
</tr>
</thead>
<tfoot>
<tr>
<td> <input type="text" name="nome_campo"> </td>
<td> <button type="button" id="incluir_campo" class="btn btn-link">Incluir</button> </td>
</tr>
<tr>
<td> <div id="result_incluir_campo"></div> </td>
<td> <div id="result_excluir_campo"></div> </td>
</tr>
</tfoot>
<c:forEach var="item_key" items="${campos}">
<tr id="linha_campo_${item_key}">
<td> <input type="text" value="${item_key}"> </td>
<td> <button type="button" id="excluir_campo_${item_key}" class="btn btn-link">Excluir</button> </td>
</tr>
</c:forEach>
</table>
Note the line:
<button type="button" id="excluir_campo_${item_key}" class="btn btn-link">Excluir</button>
I have one jquery function associated to it:
<c:forEach var="item_key" items="${campos}">
<script>
$("#excluir_campo_${item_key}").on("click", function () {
$.ajax({
type: "GET",
url: "<c:out value="${pageContext.request.contextPath}/key/remove_campo"/>",
cache: false,
data: {nome: "${item_key}"}
}).done(function(data){
if(data == "yes") {
$("#linha_campo_${item_key}").remove();
}
else if(data == "not"){
$("#result_excluir_campo").empty().append("erro");
}
else {
$("#result_excluir_campo").empty().append("sem acesso");
}
});
});
</script>
</c:forEach>
I was using jstl, but i am facing some problems with this solution, since my list can be updated dynamicly.
Take in consideration I change the Id from this element:
<button type="button" id="excluir_campo_${item_key}" class="btn btn-link">Excluir</button>
to this two (separating the two "terms" of current Id):
excluir_campo ${item_key}
is there any way to detect the secong id with a jquery function similar to that:
$("#excluir_campo").on("click", function () {
var second_id = ???;
$.ajax({
type: "GET",
url: "<c:out value="${pageContext.request.contextPath}/key/remove_campo"/>",
cache: false,
data: {nome: "<second_id>"}
}).done(function(data){
if(data == "yes") {
$("#linha_campo_<second_id>").remove();
}
else if(data == "not"){
$("#result_excluir_campo").empty().append("erro");
}
else {
$("#result_excluir_campo").empty().append("sem acesso");
}
});
});
Or there is another way to accomplish the same result of the code above?
First of all, never generate scripts in rendered html using any kind of loops. What if you have 1000 items? 1000 times your code, very inefficient. You can use write a generic function and render that caller. This way, you save thousands of lines!
Secondly, NEVER use generated id's and id based functions, never ever! you can just use a generic class for that functionality, you do not need id selector. You just need an extra attribute like "key":
<div class="my-functionality" data-key="15" />
<div class="my-functionality" data-key="16" />
<div class="my-functionality" data-key="17" />
<div class="my-functionality" data-key="18" />
And you can just use either generated scripts in loops or jquery's each selector to bind events to your elements: you can wrap your click event like:
$('.my-functionality').each(function(index, elem){
$(elem).click(function(){
//do you stuff here!
var key = $(elem).data('key'); //this will read data-key attribute
});
});

deleting entire row with jquery json ajax php

What I want to achieve is to delete an entire row. First I display the table, then if you click on "delete" button from every row then a confirmation modal shows up asking you if you want to delete that row.
I'm trying to work with jquery, ajax, json and PHP. I'm still learning of course.
So far what I have is this:
Javascript file:
function callToModal(data){
$('#myModal3 .modal-body p').html("Desea eliminar al usuario " + '<b>' + data + '</b>' + ' ?');
$('#myModal3').modal('show');
$('.confirm-delete').on('click', function(e) {
e.preventDefault();
var id = $(this).data('id');
$('#myModal3').data('id', id).modal('show');
});
$('#btnYes').click(function() {
// handle deletion here
var id = $('#myModal3').data('id');
alert(id);
$.ajax({
url: "deleteFrontUser",
type: 'POST',
data: {
id:id
},
success: function(html){
//alert(html);
$('[data-id='+id+']').parents('tr').remove();
$('#myModal3').modal('hide');
}
});
return false;
});
};
In my admin.php file:
public function deleteFrontUser(){
// var_dump($_POST['id']);die();
$rowId = $_POST['rowId'];
$result = array();
$front = UserDs::getInstance()->getUserById($id);
UserDs::getInstance()->deleteItem($front);
$result["message"] = "Usuario eliminado";
echo json_encode($result);
}
The view (please notice that I'm using Smarty template engine):
<div class="portlet-body">
<table class="table table-striped table-hover table-users">
<thead>
<tr>
<th>Avatar</th>
<th class="hidden-phone">Usuario</th>
<th>Nombre</th>
<th>Apellido</th>
<th class="hidden-phone">Email</th>
<th class="hidden-phone">Provincia</th>
<th class="hidden-phone">Miembro desde</th>
<th>Estado</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{foreach $frontusers as $frontuser}
<tr>
{if $frontuser->frontavatar_id eq null}
<td><img src="{site_url()}assets/img/avatar.png" alt="" /></td>
{else}
<td><img src="{site_url()}assets/img/avatar1.jpg" alt="" /></td>
{/if}
<td class="hidden-phone">{$frontuser->username}</td>
<td>{$frontuser->name}</td>
<td>{$frontuser->lastname}</td>
<td class="hidden-phone">{$frontuser->email}</td>
<td class="hidden-phone">{$frontuser->state}</td>
<td class="hidden-phone">{$frontuser->creation_date|date_format:"%Y/%m/%d"}</td>
{if $frontuser->status eq 2}
<td ><span class="label label-success">Activo</span></td>
{else}
<td ><span class="label label-warning">No Activo</span></td>
{/if}
<td><a class="btn mini blue-stripe" href="{site_url()}admin/editFront/{$frontuser->id}">Modificar</a></td>
<td>Eliminar</td>
</tr>
<!-- modal -->
<div id="myModal3" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel3" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button>
<h3 id="myModalLabel3">Eliminar</h3>
</div>
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Cerrar</button>
<button data-dismiss="modal" class="btn red" id="btnYes">Confirmar</button>
</div>
</div>
<!-- end modal -->
{foreachelse}
<tr>
<td colspan="2"><span class="text-error"><i class="icon-exclamation"></i> No hay Usuarios cargados.</span></td>
</tr>
{/foreach}
</tbody>
</table>
</div>
The modal displays when you click on delete button of an specific row, but here's the funny thing: the first time you press delete, it doesn't erase the row. When you press that or any other row (after pressing once delete) the row is deleted. So that is one problem, and the other problem is that I can't manage to send data to my php file so I can erase it from the database.
How can i solve this?
I have a customized fiddle with this, if you want to check out: code
url has to be a valid site located within your website, you can't have a function name within url, since the AJAX call won't know in which file the function is located.
So your url must be:
url: "admin.php"
You can, however, add another parameter into your AJAXcall to tell admin.php which function it should execute, something like this would work:
$.ajax({
url: "admin.php",
type: 'POST',
data: {
id:id,
func:"deleteFrontUser"
},
success: function(html)
{
//alert(html);
$('[data-id='+id+']').parents('tr').remove();
$('#myModal3').modal('hide');
}
});
So on admin.php you must receive the posted data BEFORE you enter the function, and you can parse the func variable to tell which function to execute:
$rowId = $_POST['id'];
$func = $_POST['func'];
switch ($func)
{
case 'deleteFrontUser':
deleteFrontUser($rowId);
break;
default:
// function not found.
break;
}
Wherea deleteFrontUser looks something like this:
public function deleteFrontUser($rowId)
{
$result = array();
// Rest of the code.
echo json_encode($result);
}
Maybe you need to modify this a bit but this should give you the idea.
For more information take a look at the $.ajax documentation.
Note:
For best practice's cause, use php's isset function to determine whether the data was actually posted or not. The ternary operator makes this very easy and short:
$emptyString = "";
$rowId = isset($_POST['id']) ? $_POST['id'] : $emptyString;
$func = isset($_POST['func']) ? $_POST['func'] : $emptyString;
I also recommend using jQuery's .on function, and let it take the parameter "click" and the function of which will be triggered on the click event. .click is in general bad practice because it's unable to detect changes within the DOM tree so when you update it with new HTML you're screwed, .on allows you to add new elements to the dom tree but still being able to listen to events corresponding to them.
Solution is this:
See my previous post in order to have the correct js file and view: post
Php code for deleting entire row from the database would be:
public function deleteFrontUser(){
$rowId = $_POST['id'];
$result = array();
$front = UserDs::getInstance()->getUserById($rowId);
UserDs::getInstance()->deleteItem($front);
$result["message"] = "Usuario eliminado";
echo json_encode($result);
}

jQuery Multiple Dynamic Forms + Foreach Loop

Okay, i'm completetly stuck. I tried every answer on here but I just can't get it to work.
My Aim: Updating dynamic forms with jQuery & AJAX
What's the problem: When clicking one of the "save" buttons it only saves the first value, I tried to do it with different ID's but as a newbie to jQuery I don't think I'm doing this right.
jQuery
$(document).ready(function() {
$("textarea").keyup(function(){
var txtArea = $('.txta').val();
var scriptString = $('.button').attr("url");
$(".button").click(function(){
$.ajax({
method: 'get',
url: '../wp-content/plugins/custom-text-editor/writefile.php',
data: {
'myString': scriptString,
'txt': txtArea,
'ajax': true
},
success: function(data) {
$('#'+myString).text(data);
return false;
}
});
});
});
});
writefile.php
$file = fopen("files/tab1.txt","w");
$txt = $_GET['txt'];
fwrite($file,$txt);
fclose($file);
echo "OK!";
Generated HTML
<table class=bordered>
<tr>
<th>Filename</th>
<th></th>
<th></th>
</tr>
<tr class=header>
<td class='plus'>+</td>
<td><p>tab1.txt</p></td>
<td><span id='ss' class='data'></span></td>
</tr>
<tr>
<td colspan="3" class="nopad">
<p><textarea cols="80" class="txta" rows="12" id="tab1.txt">asdasd</textarea>
<span id='tab1.txt' class='button' rel='qyz' url=tab1.txt>Save</span></p>
</td>
</tr>
<tr class=header>
<td class='plus'>+</td>
<td><p>tab2.txt</p></td>
<td><span id='ss' class='data'></span></td>
</tr>
<tr>
<td colspan="3" class="nopad">
<p><textarea cols="80" class="txta" rows="12" id="tab2.txt">This is file 2</textarea>
<span id='tab2.txt' class='button' rel='qyz' url=tab2.txt>Save</span></p>
</td>
</tr>
<tr class=header>
<td class='plus'>+</td>
<td><p>tab3.txt</p></td>
<td><span id='ss' class='data'></span></td>
</tr>
<tr>
<td colspan="3" class="nopad">
<p><textarea cols="80" class="txta" rows="12" id="tab3.txt">And File 3</textarea>
<span id='tab3.txt' class='button' rel='qyz' url=tab3.txt>Save</span></p>
</td>
</tr>
<tr class=header>
<td class='plus'>+</td>
<td><p>tab4.txt</p></td>
<td><span id='ss' class='data'></span></td>
</tr>
<tr>
<td colspan="3" class="nopad">
<p><textarea cols="80" class="txta" rows="12" id="tab4.txt">It works!</textarea>
<span id='tab4.txt' class='button' rel='qyz' url=tab4.txt>Save</span></p>
</td>
</tr>
</table>
This should resolve your problem:
$(document).ready(function () {
$(".button").click(function () {
var txtArea = $(this).closest('tr').find('.txta').val();
var scriptString = $(this).closest('tr').find('.button').attr("url");
$.ajax({
method: 'get',
url: '../wp-content/plugins/custom-text-editor/writefile.php',
data: {
'myString': scriptString,
'txt': txtArea,
'ajax': true
},
success: function (data) {
$('#' + myString).text(data);
return false;
}
});
});
});
How it works:
$(this) gives access to an element being clicked. Even "this" (without dollar sign and without quotes) gives such access, but it is not a jquery object, we need jquery object for further manipulations.
closest('tr') iterates the chain of parent elements until it finds an element satisfying the specified selector (in this case it searches for closest tr-element).
find('.txta') iterates the descendants (of the current element) until it finds an element satisfying the specified selector (in this case it searches for any element having "txta" class, within the tr element).
The rest of code is unchanged.
Further notes:
Event handlers within event handlers (like $("textarea").keyup(function(){ ... $(".button").click(function() { ... ) should be avoided, since the effect is: each time an outer event is handled, a new handler for the inner event is created and attached.
Think of jquery as being kind of "navigation system" over DOM-tree. With functions like "closest", "find", "next", "prev" you navigate around and get to the desired element dynamically, at runtime.
When the desired object has ID and is unique, address it with "#ID" syntax.
When the desired object is repeated (like a row/cell within the table or an element within the cell), then use css-classes and DOM-traversal functions in order to address it.
If you need more information on DOM-traversing:
http://learn.jquery.com/using-jquery-core/traversing/
http://api.jquery.com/category/traversing/

Categories

Resources