How can i update data in html after modify the object? - javascript

I have this function that modify my existing object by ID :
var updateUser = function () {
var id = $("#userId").val();
var user = findObjectById(id);
user.username = $('#username').val();
user.level = $('#level').val();
user.regstatus = $('#regstatus').val();
user.regdate = $('#regdate').val();
$(".table").show();
$("#newUser").show();
$("#userForm").hide();
$("#updateUser").hide();
};
How can i replace my curent data from HTML with modified data ?
This is my function for creating rows :
var buildRow = function (data) {
var html = '<tr id = ' + data.id + '>' +
'<td>' + data.username + '</td>' +
'<td>' + data.level + '</td>' +
'<td>' + data.regstatus + '</td>' +
'<td>' + data.regdate + '</td>' +
'<td>' +
'<button class="btn btn-info"value="Edit" onclick="userList.editUser(' + data.id + ')">Edit</button>' + ' ' +
'<button class="btn btn-danger" value="Delete" onclick="userList.deleteRow(' + data.id + ')">Delete</button>' + '</td>' +
'</tr>';
$("#users").append(html);
};
P.S i want to update in the same place and my id should be the same.

I modified your prototype jsFiddle a bit, so it contains a working example.
I needed to modify some parts to get it work, for example updating the object I added a function.
updateObjectById = function (id, obj){
for (var i = 0, l = userData.length; i < l; i++) {
if (userData[i].id == id) {
userData[i] = obj;
}
}
};
You should be able to work it out I guess, by the given jsFiddle

As I understand it you want to update the table when running "updateUser". There are basically three ways to update the data in your case.
Rebuild the whole row
Pick out specific cells in the table and change the content
Use a two way databinding framework
In my experience the best solution, and how f.ex. Backbone does it, is just recreating all the HTML when your data changes. two way databinding is even more powerful, but seems overkill in this situation.
So basically in your updateUser function:
var row = buildRow(user);
var $existingRow = $(id);
if ($existingRow.length) {
$existingRow.replaceWith(row);
} else {
$('#users').append(row);
}
Now, this of course requires a change to your "buildRow" function, not making it append the row, but return it.
Hope this gets you further...

Related

Coffeescript : For loop to concatenate HTML <td> element

Playing around a coffeescript. I have the following for loop to concat a html element in native javascript which works well. At the moment I just couldnt get the value json data i.e i.a , i.b from coffeescript.
//.js file
function createTr(json){
var tr='';
for (var i=0;i<json.data.length;i++){
var data ='<tr><td>' + json.data[i].a + ' - ' + json.data[i].b +
'</td>'+
'<td>' + json.data[i].c +
'</td>'+
'<td>' + json.data[i].d +
'</td>'+
'</tr>';
tr +=data;
}
return tr;
}
The coffescript is per below
//.coffeescript
createTr = (json) ->
tr=''
tr + '<tr><td>' + i.a + '-' + i.b+'</td> <td>'+i.c+'</td><td>'+i.d+'</td></tr>' for i in json.data
tr
the source map for the autogenerated javascript from the coffeescript as per below
//autogenerated js file from coffeescript file above
createTr = function(json) {
var i, j, len, ref, tr;
tr = '';
ref = json.data;
for (j = 0, len = ref.length; j < len; j++) {
i = ref[j];
tr + '<tr><td>' + i.a + '-' + i.b + '</td><td>' + i.c + '</td><td>' + i.d + '</td></tr>';
}
return tr;
};
The only difference is a missing assignment. The CoffeeScript version should be:
createTr = (json) ->
tr=''
tr += '<tr><td>' + i.a + '-' + i.b+'</td> <td>'+i.c+'</td><td>'+i.d+'</td></tr>' for i in json.data
tr
##.coffee file
createTr = (json) ->
tr = ''
for item in json.data
data = """<tr>
<td>#{item.a}-#{item.b}</td>
<td>#{item.c}</td>
<td>#{item.d}</td></tr> """
tr += data
return tr
And read http://coffeescript.org/ about loop, string and variables in string like "Some text #{variable}"
I prefer to use a join on the array that the for loop creates:
createTr = (json) ->
('<tr><td>' + i.a + '-' + i.b+'</td> <td>'+i.c+'</td><td>'+i.d+'</td></tr>' for i in json.data).join("")
or kind of like #yavor.makc if it was my code I might focus on readability:
createTr = (json) ->
(for i in json.data
"
<tr>
<td>#{i.a}-#{i.b}</td>
<td>#{i.c}</td>
<td>#{i.d}</td>
</tr>
"
).join("")

How to optimize the DOM inserting loop

For example : I want to insert many tr in a table like this
var tbody = $('#tbody')
// Suppose the articlelist is the data from ajax
while (articlelist.length > 0) {
var article = articlelist.shift(),
var tr = $(' <tr>'
+' <td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><td>'
)
tbody.append(tr)
}
To avoid create the <tr>...</tr> in loop .Is it possible to use a class to generate the tr content ?
An optimized version:
var tbody = $('#tbody'),
htmlStr = "";
for (var i = 0, len = articlelist.length; i < len; i++) { // avoid accessing 'length' property on each iteration
htmlStr += '<tr><td>' + articlelist[i].id + '</td>'
+ '<td>' + articlelist[i].channelid + '</td>'
+ '<td>' + articlelist[i].comment + '</td>'
+ '<td>' + articlelist[i].last_edit_time + '</td><td><tr>';
}
tbody.append(htmlStr); // parses the specified text as HTML or XML and inserts the resulting nodes
You could use a loop to concatenate all the strings, then append this lengthy string all at once. This would help with performance for many trs
var tbody = $('#tbody')
var rows = ''
while (articlelist.length > 0) {
var article = articlelist.shift(),
rows += '<tr><td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><tr>';
}
tbody.append(rows)
add a function like this to do this for you.
while (articlelist.length > 0) {
make_content(article);
}
function make_content(article) {
var tbody = $('#tbody');
var tr = $(' <tr>'
+' <td>'+article.id+'</td>'
+'<td>' + article.channelid +'</td>'
+ '<td>'+article.comment+'</td>'
+'<td>'+article.last_edit_time+'</td><td>'
)
tbody.append(tr)
}

How do i find index of my object?

I have a table that is dynamicaly created something like this:
userData = Object Object Object...etc;
Object= username : ....
level:
regdate:
JavaScript code:
var buildTable = function () {
for (var i = 0, l = userData.length; i < l; i++) {
buildRow(userData[i]);
}
var buildRow = function (data) {
var html = '<tr><td>' + data.username + '</td>' +
'<td>' + data.level + '</td>' +
'<td>' + data.regstatus + '</td>' +
'<td>' + data.regdate + '</td>' +
'<td>' +
'<button value = "edit" id = "edit" onclick="tableOfUsers.editUser()">Edit</button>' +
'<button value= "delete" id = "delete" onclick="tableOfUsers.deleteUser()">Delete</button>' + '</td>';
$('#tableBody').append(html);
};
I have edtiUser/deleteUser function and i want when i click on edit/delete to edit/delete my row , my question is how do i find index of my object that i want to edite/delete without haveing an id field just with index of my objects?
Modify your code like this
for (var i = 0, l = userData.length; i < l; i++) {
buildRow(userData[i], i);
}
and
var buildRow = function (data, index) {
and
'<button value = "edit" id = "edit" onclick="tableOfUsers.editUser('+index+')">Edit</button>' +
'<button value= "delete" id = "delete" onclick="tableOfUsers.deleteUser('+index+')">Delete</button>' + '</td>';
$('#tableBody').append(html);
notice that we are passing index to the method being called from inside html strings.

Prevent javascript function from generating delete action links if a logged in user role is Associate

I got two different roles, Admin and Associate.
An Admin should be able to delete a product while an Associate should not be able to delete a product.
I know how to configure this in the View by not showing the Delete Action Link for an logged in Associate user. However I have also implemented an onkeydown ajax search functionality that returns a list of jsonobjects. These json-objects are a list of product objects that matches the searchstring and then immediately builds up the markup in the view. This is done from a single javascript function.
The problem with this is that it now is hardcoded to generate delete action links, regardless of current logged in user role. So in a way, I need to modify my javascript function so that it doesn't generate delete actionlinks if the current logged in user is an associate user.
This is my function:
function searchProduct() {
var searchWord = $('#searchString').val();
$.ajax({
url: '/Product/TextChangeEventSearch?searchString=' + searchWord,
type: 'GET',
datatype: 'json',
contenttype: 'application/json',
success: function (data) {
$('.table tr:gt(0)').detach();
$.each(data, function (i, item) {
$('.table').append('<tr>' +
'<td>' + item.Name + '</td>' +
'<td>' + item.Status + '</td>' +
'<td>' + item.Genre + '</td>' +
'<td>' + '<a href=/Product/Edit/' + item.Value + '>Edit</a> |' +
'<a href=/Product/Details/' + item.Value + '>Details</a> |' +
'<a href=/Product/Stock/' + item.Value + '>Stock</a> |' +
'<a href=/Product/Discount/' + item.Value + '>Discount</a> |' +
'<a href=/Product/Delete/' + item.Value + '>Delete</a>' +
'</td>' +
'</tr>'
);
});
}
});
}
Triggered by this in the View:
<div class="form-group">
#Html.TextBox("searchString", "", new { onkeydown = "searchProduct();", onkeyup = "searchProduct();", onkeypress = "searchProduct();"})
<input type="submit" value="Search" class="btn btn-default" onclick="searchProduct()"/>
</div>
My Server code in the controller:
public JsonResult TextChangeEventSearch(string searchString)
{
var products = _productRepository.GetAll().ToList();
var result = products.Where(p => p.Name.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0).OrderByDescending(x => x.Status).ThenBy(y => y.Name);
var jsonList = result.Select(p => new
{
Name = p.Name,
Status = p.Status,
Genre = p.Category.Name,
Value = p.Id.ToString(),
Warehouse = p.Stock
});
return Json(jsonList.ToList(), JsonRequestBehavior.AllowGet);
}
I think that I need access to the current logged in user role in the javascript function. Then I might be able to add one if statement in the function that prevents it from generating delete action links in the view if it is an associate user that uses this function.
Where do I go next with this? Any thoughts, explanations and help would be greatly appreciated.
May be you can render the role of the current user in one hidden field on the page and then use the value of that field to decide if delete button should be rendered.
#{
Layout = Model.Layout;
var isAssociate = Context.User.IsInRole("Associate"); //This is indicative and one of the approach of getting user role information at the client side. You can have your own mechanism to get the user's role information at the client side so that you can use it in your javascript.
}
<input type="hidden" value="#isAssociate"/>
and your javascript call will look like as following.
function searchProduct() {
var searchWord = $('#searchString').val();
var isAssociate = $('#isAssociate').val();
$.ajax({
url: '/Product/TextChangeEventSearch?searchString=' + searchWord,
type: 'GET',
datatype: 'json',
contenttype: 'application/json',
success: function (data) {
$('.table tr:gt(0)').detach();
$.each(data, function (i, item) {
var htmlContent = '<tr>' +
'<td>' + item.Name + '</td>' +
'<td>' + item.Status + '</td>' +
'<td>' + item.Genre + '</td>' +
'<td>' + '<a href=/Product/Edit/' + item.Value + '>Edit</a> |' +
'<a href=/Product/Details/' + item.Value + '>Details</a> |' +
'<a href=/Product/Stock/' + item.Value + '>Stock</a> |' +
'<a href=/Product/Discount/' + item.Value + '>Discount</a> ';
if(isAssociate == "false")
{
htmlContent += |' + '<a href=/Product/Delete/' + item.Value + '>Delete</a>'
}
htmlContent += '</td>' + '</tr>'
$('.table').append(htmlContent);
});
}
}
});
NOTE : Here I am assuming that you have figured out a mechanism to identify the user role and you are able to store it so that it can be accessed in the view. If you don't have this then you need to figure out a way for that.
I am sure this will help you.
Thanks and regards,
Chetan Ranpariya
you're on the right track. the js needs to know! you could add a data attribute to the input, for example:
<input data-is-admin="false" ....>
and then check this attribute in the js. and you'll propably want to authorize any delete on your server anyway.
Once you have the data in JavaScript you can use an online if statement to only show delete button for admin:
'...' + ( userRole == 'Admin' ? '[Delete button HTML]' || '') + '...'
It's been a while, but I got back to this issue many weeks later, and I solved it like this:
At the top of the view:
#{
ViewBag.Title = "Index";
var isAdmin = Context.User.IsInRole("Admin");
}
Javascript function:
function searchProduct() {
var searchWord = $('#searchString').val();
var isAdmin = "#isAdmin";
$.ajax({
url: '/Product/TextChangeEventSearch?searchString=' + searchWord,
type: 'GET',
datatype: 'json',
contenttype: 'application/json',
success: function (data) {
$('.table tr:gt(0)').detach();
$.each(data, function (i, item) {
var htmlContent = '<tr>' +
'<td>' + item.Name + '</td>' +
'<td>' + item.Status + '</td>' +
'<td>' + item.Genre + '</td>' +
'<td>' + '<a href=/Product/Edit/' + item.Value + '>Edit</a> | ' +
'<a href=/Product/Details/' + item.Value + '>Details</a> | ' +
'<a href=/Product/Discount/' + item.Value + '>Discount</a> ';
if (isAdmin.toString() === "True")
{
htmlContent += '| ' + '<a href=/Product/Delete/' + item.Value + '>Delete</a>'
}
htmlContent += '</td>' + '</tr>'
$('.table').append(htmlContent);
});
}
});
}

passing value to a dynamic created function in javascript

I am having some problems while creating a dynamic webpage in javascript.
My idea is to read a list of events and people signed up on them. I create a page with all events (each event is a button) and clicking on one of them, see the list of users.
This works fine. But now, I am adding a button to export some of these users to an excel file. And I want to add a button with an onClick function like this:
...onclick=functionÇ(id_Event, numberOfUsers, listOfUsers)...
Inside of the html code generated by javascript. I found some problems also doing like this so I changed so:
var td = document.createElement("td");
var input = document.createElement("input");
input.setAttribute("type","button");
input.setAttribute("value","Exportar a Excel CSV");
input.onclick = function() {
saveExcelFunctionControl(arrayNumberUsersInEvents[i], response);
};
td.appendChild(input);
document.getElementById("added"+element[i].id_Event).appendChild(td);
I created a global array called arrayNumberUSersInEvents in which I am adding in each possition, people subscribed. i, is the id counter for each position.
But even this, I am getting an undefined while reading the value of the firsdt parameter. I think it is a problem of dynamic data, I am not executing the function I want to each time I click the button. Do you know how to do something like this?
To sum up: My problem is that I want to pass some arguments to a function in a dynamic created page. I don't know how to pass the data and read the correct parameters inside.
I added my code because one user asked for it:
for(i = 0; i < element.length; i++){
$(".eventsControl").append(
'<li id="listControl'+ element[i].id_Event +'">'+
'<a href="#EventControl' + element[i].id_Event + '"' + 'data-transition="slidedown">'+
'<img class="crop" src= "' + element[i].image + '" />'+
'<h2>' + element[i].name + '</h2>'+
'<p>' + "Desc: " + element[i].description +'</p>'+
'</a>'+
'</li>'
).listview('refresh');
//console.log(response);
//BUCLE for setting all users in each event. Better use some string and after, join all of them
header = ' <div width="100%" data-theme = "e" data-role="page" id='+ element[i].id_Event +
' data-url="EventControl' + element[i].id_Event + '"> ' +
' <div data-theme = "a" data-role="header"><h1>Lista de Asistencia</h1> ' +
' </div>'+
' <div data-role="content"> ' +
' <fieldset data-role="controlgroup" data-type="horizontal" style="text-align: center">' +
' <div style="width: 500px; margin: 0 auto;">';
//header = header + '<input data-theme = "c" onclick="saveExcelFunctionControl(this)" id="saveExcelControl' + element[i].id_Event + '" type="button" value = "Guardar a excel"></br>';
eval('var numberUsers' +element[i].id_Event + "=1");
arrayNumberUsersInEvents[i] = 0;
if(response.length>0){
bucle = ' <table width="100%" border="1" align="left"><tr>'+
' <th>Nombre</th>'+
' <th>Primer apellido</th>'+
' <th>Segundo apellido</th>'+
' <th>NIF</th>'+
' <th>Asistencia</th>'+
' </tr>';
for(iData = 0; iData < response.length; iData++){
if(element[i].id_Event == response[iData].id_Event){
//console.log(response[iData].name);
bucle = bucle + '<tr><td>'+ eval('numberUsers' +element[i].id_Event) +'</td><td>'+ response[iData].name +'</td><td>'+
response[iData].surname1 +'</td><td>'+
response[iData].surname2 +'</td><td>'+
response[iData].NIF + '</td>'+
'<td> '+
'<input type="checkbox" id="checkBox'+element[i].id_Event+'_'+iData+'" name="option'+iData+'" value="'+iData+'"> '+
'</td>'+
'</tr>';
eval('numberUsers' +element[i].id_Event + "++");
arrayNumberUsersInEvents[i] = arrayNumberUsersInEvents[i]+1;
}
}
//header = header + '<input data-theme = "a" onclick="saveExcelFunctionControl(\""element[i].id_Event "\","" + numberUsers + "\",\"" + response+ "\"")" id="saveExcelControl' + element[i].id_Event + '" type="button" value = "Guardar a excel"></br>';
//header = header + '<input data-theme = "a" onclick="saveExcelFunctionControl(""+numberUsers+"")" id="saveExcelControl' + element[i].id_Event + '" type="button" value = "Guardar a excel"></br>';
bucle = bucle + '</table>';
$("#controlList").after(header + bucle + '<div id=added'+element[i].id_Event+'></div>');
var td = document.createElement("td");
var input = document.createElement("input");
input.setAttribute("type","button");
input.setAttribute("value","Exportar a Excel CSV");
input.onclick = function() {
saveExcelFunctionControl(arrayNumberUsersInEvents[i], response);
};
td.appendChild(input);
document.getElementById("added"+element[i].id_Event).appendChild(td);
}
}
},
error: function(xhr, status, message) { alert("Status: " + status + "\nControlGetEventsRegister: " + message); }
});
You can use closure to pass parameters to dynamically created onclick handler:
input.onclick = (function() {
var arr = arrayNumberUsersInEvents[i];
var resp = response;
return function() {
saveExcelFunctionControl(arr, resp);
}
})();
How do JavaScript closures work?
var td = document.createElement("td");
var input = "<input type='button' value='Exportar a Excel CSV'";
input+= "onclick='saveExcelFunctionControl(""" +arrayNumberUsersInEvents[i]+""","""+ response+""");' />";
};
td.textContent=input;
document.getElementById("added"+element[i].id_Event).appendChild(td);
try this way

Categories