Refreshing ViewModel after deleting data in Knockout.js - javascript

I am using Knockout for binding data of a form to the table,now what i ma facing is that when i am deleting the data from the table it goes to server side and delete the data as well but that data remains there unless we refresh the page which not pratical.So what i tried that i am calling the index method on server side which gives me the list of the datas after refreshing the database but when i am doing this.that refreshed datas are appended to the data that remain on the view.i mean it shows the remaing datas and refreshed data both but pratically it shows only the refreshed datas.
My code:
<table id="table2" style="border: double">
<thead>
<tr>
<td>Ticket ID</td>
<td>Ticket Type</td>
<td>No of Tickets</td>
<td>Ticket Price</td>
<td>Start Date</td>
<td>End Date</td>
<td>Action</td>
</tr>
</thead>
<!--Iterate through an observableArray using foreach-->
<tbody id="ticketid" data-bind="foreach:TicketDatas">
<tr style="border: solid" data-bind="click: $root.getselectedTicket" id="updtr">
<td data-bind="text:TicketId">#*<span data-bind="text:No_Of_Ticket"></span>*#</td>
<td data-bind="text:SelectedTicketType">#*<span data-bind="text:No_Of_Ticket"></span>*#</td>
<td data-bind="text:No_Of_Ticket">#*<span data-bind="text:No_Of_Ticket"></span>*#</td>
<td data-bind="text:Ticket_Price">#*<span data-bind="text:Ticket_Price"></span>*#</td>
<td data-bind="text:Start_Date">#*<span data-bind="text:Start_Date"></span>*#</td>
<td data-bind="text:End_Date">#*<span data-bind="text:End_Date"></span>*#</td>
<td><button id="deletelink">Delete</button></td>
</tr>
</tbody>
</table>
<script type="text/javascript">
$("#deletelink").live('click', function () {
if (confirm('Are you sure to Delete this ticket ??')) {
var deleteLink = $(this);
var tableRow = deleteLink.closest('tr');
var firstCell = tableRow.find('td:first-child');
var tickid = firstCell.text();
//var tickid = $("#table2 tbody tr td:eq(0)").html();
$.ajax({
type: "POST",
data: { id: tickid },
url: "Ticket/DeleteTicket",
//data: "{id:" + ko.toJSON(id) + "}",
success: function (data) {
self.TicketDatas.remove(data);
alert("Record Deleted Successfully");
//ko.mapping.fromJS(self.TicketDatas, data)
//GetTickets();//Refresh the Table
},
error: function (error) {
alert(error.status + "<--and--> " + error.statusText);
}
});
// alert("Clicked" + employee.EmpNo)
}
});
function GetTickets() {
//Ajax Call Get All Employee Records
$.ajax({
type: "GET",
cache: false,
url: "Ticket/GetAllTickets",
contentType: "application/json; charset=utf-8",
data: {},
dataType: "json",
success: function (data) {
for (var i = 0; i < data.length; i++) {
self.TicketDatas.push(data[i]);
}
},
error: function (error) {
alert(error.status + "<--and--> " + error.statusText);
}
});
//Ends Here
}
</script>

In your ajax call, I notice you have a success handler like this:
success: function (data) {
self.TicketDatas.remove(data);
alert("Record Deleted Successfully");
//ko.mapping.fromJS(self.TicketDatas, data)
//GetTickets();//Refresh the Table
},
I can see where you're trying to remove the deleted item by calling self.TicketDatas.remove(data);. However, this isn't likely to remove anything from your client-side array of TicketDatas, because you're using the data from the response of the ajax call, and trying to remove that literal object from the array. That actual object isn't in the array, because it was just created from the ajax response.
When removing an object from an array, you either need to reference it by index, or by the an object reference which points to the same memory address as an object in the array.
Try something like this instead:
success: function (data) {
self.TicketDatas.remove(ko.dataFor(deleteLink));
...
},
http://knockoutjs.com/documentation/unobtrusive-event-handling.html

Why bother trying to remove a single ticket from your array when shortly after you ask for all tickets? Also I imagine you don't actually want to use a 'push' if GetTickets really is returning all tickets.
<script type="text/javascript">
$("#deletelink").live('click', function () {
if (confirm('Are you sure to Delete this ticket ??')) {
var deleteLink = $(this);
var tableRow = deleteLink.closest('tr');
var firstCell = tableRow.find('td:first-child');
var tickid = firstCell.text();
**DeleteTicket(tickid);**
}
});
function DeleteTicket(tickid) {
$.ajax({
type: "POST",
data: { id: tickid },
url: "Ticket/DeleteTicket",
success: function (data) {
alert("Record Deleted Successfully");
**GetTickets()**
},
error: function (error) {
alert(error.status + "<--and--> " + error.statusText);
}
});
}
function GetTickets() {
//Ajax Call Get All Employee Records
$.ajax({
type: "GET",
cache: false,
url: "Ticket/GetAllTickets",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
**self.TicketDatas(data);**
},
error: function (error) {
alert(error.status + "<--and--> " + error.statusText);
}
});
//Ends Here
}
</script>

Related

select2 returning position of items, not ID of items

I'm using a select2 to allow the user to select multiple options. Everything is working fine, except for one frustrating issue.
The first time I click the save button to save the items, it works. But then on subsequent calls, the ID of the items are replaced with the position of the items. For for example, if I have IDs 3, 6 and 10 selected, the first Save will work and 3,6,10 are passed to the controller.
But then if I reload the view and click save, the numbers 0,1,2 are passed in (ie, their relative positions in the select).
Here is the code:
Firstly, the HTML:
<select id="selectGroup" class="form-control" multiple="true">
On $(document).ready:
// Load Groups
$("#selectGroup").select2({ placeholder: 'Select' });
$.ajax({
url: ROOT_URL + "Group/GroupList",
type: "GET",
success: function (data) {
let dropdown = $('#selectGroup');
dropdown.empty();
dropdown.append($('<option></option>').attr('value', 0).text("(Select)"));
$.each(JSON.parse(data), function (key, entry) {
dropdown.append($('<option></option>').attr('value', entry.GroupID).text(entry.GroupName));
})
},
error: function (passParams) {
Notify(passParams, "Unexpected Error Loading Groups", "error");
}
});
And finally the js for the save (called from a button which passes in the loanID):
function LoanGroupSave(loanID) {
var grpIDs = '';
[].forEach.call(document.querySelectorAll('#selectGroup :checked'), function (elm) {
grpIDs += elm.value + ',';
})
var editURL = location.protocol + '//' + location.host + "/Loan/LoanGroupSave";
//alert(editURL);
var obj = { "LoanID": loanID, "GroupIDs": grpIDs };
alert(JSON.stringify(obj));
$.ajax({
type: "POST",
url: editURL,
data: JSON.stringify(obj),
contentType: "application/json; charset=utf-8",
dataType: "json",
}).done(function (response) {
if (response.success) {
Notify("Group(s) information has been saved", "Saved", "success", false, "toast-top-right", 5000);
}
else {
OpenPopupGeneral("Error(s)", response.message);
}
}).fail(function (jqXHR, textStatus, errorThrown) {
OpenPopupGeneral("Unexpected Error(s)", "Error = " + errorThrown);
});
}
Posting for people who make the same mistake.
Problem was in my load - I needed to add the GroupID as the key, not the row number which was in the key parameter value:
success: function (data) {
$.each(JSON.parse(data), function (key, entry) {
var $newOption = $("<option selected='selected'></option>").val(entry.GroupID).text(entry.GroupName);
$("#selectGroup").append($newOption).trigger('change');
}

Data not binding to table using KnockoutJS

I am working on my first custom-built KO implementation and I had the data binding to the table in my page, but not it's not binding to it. I can verify that my web service is getting called and it's returning data. However, I don't know why the data isn't loading into the table since I am not getting any errors.
I am sure I am missing something simple since I am a newb to this. :)
I am using KO 3.1.0.
PAGE MARKUP
<table class="dnnGrid">
<thead>
<tr class="dnnGridHeader">
<th>Task ID</th>
<th>Name</th>
<th>Description</th>
<th>Date Updated</th>
</tr>
</thead>
<tbody data-bind="foreach: tasks">
<tr class="dnnGridRow">
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Description"></td>
<td data-bind="text: LastUpdatedDate"></td>
</tr>
</tbody>
</table>
PAGE SCRIPT
var sf = $.ServicesFramework(<%=ModuleId %>);
var userId = <%=UserId%>;
var serviceUrl = sf.getServiceRoot('POC');
var moduleId = sf.getModuleId();
$(document).ready(function() {
ko.applyBindings(TaskViewModel);
GetTasks();
$('#lnkSave').click(function() {
SaveTask();
GetTasks();
});
});
IMPORTED SCRIPT
var Task = function(data) {
data = data || {};
var self = this;
self.ID = ko.observable(data.ID);
self.ModuleId = ko.observable(data.ModelId);
self.ContentItemId = ko.observable(data.ContentItemId);
self.Name = ko.observable(data.Name);
self.Description = ko.observable(data.Description);
self.LastUpdatedDate = ko.observable(data.LastUpdatedDate);
self.LastUpdatedBy = ko.observable(data.LastUpdatedBy);
}
var TaskViewModel = function(items) {
var self = this;
var newTask = {
'ID': ko.observable(),
'ModuleId': ko.observable(),
'ContentItemId': ko.observable(),
'Name': ko.observable(),
'Description': ko.observable(),
'LastUpdatedDate': ko.observable(),
'LastUpdatedBy': ko.observable()
};
self.tasks = ko.observableArray(ko.utils.arrayMap(items, function (data) {
return new Task(data);
}));
self.updateTask = function (task) {
GetTasks();
}
}
function SaveTask() {
var task = {
'ModuleId': moduleId,
'LastUpdatedBy': userId,
'Name': $('#txtName').val(),
'Description': $('#txtDescription').val()
}
$.ajax({
type: 'POST',
url: serviceUrl + 'Task/CreateTask',
data: JSON.stringify(task),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
beforeSend: sf.setModuleHeaders,
success: function (data) {
var results = $.parseJSON(data);
ParseResults(results, viewModel);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("STATUS: " + xhr.status + "\nERROR:\n" + thrownError);
}
});
}
function GetTasks() {
if (TaskViewModel) {
if (TaskViewModel.tasks) {
TaskViewModel.tasks.removeAll();
}
}
$.ajax({
type: 'GET',
url: serviceUrl + 'Task/GetTasks?ModuleId=' + moduleId,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
beforeSend: sf.setModuleHeaders,
success: function (data) {
var results = $.parseJSON(data);
TaskViewModel.tasks = results;
},
error: function (xhr, ajaxOptions, thrownError) {
alert("STATUS: " + xhr.status + "\nERROR:\n" + thrownError);
}
});
}
Try moving this line ko.applyBindings(TaskViewModel) to bottom of .ready function
$(document).ready(function() {
GetTasks();
$('#lnkSave').click(function() {
SaveTask();
GetTasks();
});
ko.applyBindings(TaskViewModel);
});
After this line, var results = $.parseJSON(data); add a debugger; statement and open chrome developer tools (F12 key), refresh the page and step through the code using F10 key.
At this point you should be able to see the parsed data in results. If it is not in required format, you may need to assign TaskViewModel.tasks like this
TaskViewModel.tasks = ko.utils.arrayMap(results, function (task) {
return new Task(task);
});

Autocomplete textbox in asp.net mvc4 using ajax and jQuery

I am trying to fetch company name in textbox as autocomplete. When I run my project, Ajax will call the success function, and the record is also fetched correctly, but there are no autocomplete suggestions in the textbox.
My view is:
$("#idcompanyname").autocomplete({
source: function (request, response) {
var customer = new Array();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: '#Url.Action("Companymap", "admin")',
data: "{'term':'" + document.getElementById('idcompanyname').value + "'}",
dataType: "json",
success: function (data) {
alert(data)
response($.map(data, function (v, i) {
var text = v.vcCompanyName;
alet(text)
if (text && (!request.term || matcher.test(text))) {
return {
label: v.vcCompanyName,
value: v.kCompanyId
};
}
}));
},
error: function(result) {
alert("No Match");
}
});
}
});
}
Here is Method on controller:
var query = db.tbaccounts.Where(t => t.vcCompanyName.ToLower()
.StartsWith(term)).ToList();
List<string> lst = new List<string>();
foreach (var item in query)
{
lst.Add(item.vcCompanyName);
}
return Json(lst, JsonRequestBehavior.AllowGet);
Here is the referred Javascript:
<script src="~/script/jquery-2.0.3.js"></script>
<script src="~/script/jquery-ui.js"></script>
<script src="~/js/jquery-1.10.2.js"></script>
<script src="~/js/jquery-ui.js"></script>
Please try removing
~/script/jquery-2.0.3.js
from the script references in your application, and that should work for you....

Adding Item to list on click Javascript/Jquery

So i have list that is created dynamically as shown
Now I need a ADD button, which on click will add new item to list automatically. Help me out with this please.
Hi this is how can you retrive data using jquery
$(document).ready(function () {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "URL/MethodName",
data: "{}",// you can provide parameteres to your function here
dataType: "JSOn",
success: function (data) {
for (var i in data) {
alert(data[i].Id); //assign to controls
alert(data[i].Header);// assign to controls
alert( data[i].Content) ;// assign to contols
}
alert('Data fetched Successfully');
},
error: function (result) {
alert('Data not fetched ');
return false;
}
});
return false;
});
/*************************************************************************
[System.Web.Services.WebMethod]
public ActionResult Careers()
{
List<JobOpening> job = new List<JobOpening>()
{
new JobOpening{Id = 1, Header = "Job1", Content = "edde" },
new JobOpening{Id = 2,Header = "Job2", Content = "deded" },
};
}

Knockout.js Observable Array with onlick event

Hi I have a web application, I'm very new to KnockOut.js
I have my JS COde
ko.applyBindings(new LOBViewModel());
//COMMENTED SECTION BINDS THE DATA TO HTML, BUT DOES NOT TRIGGER ONLICK EVENT
//function LOBViewModel() {
// var self = this;
// self.vm = {
// LOBModel: ko.observableArray()
// };
// GetLOB();
//
// self.DeleteRecord = function (lobmodel) {
// $.ajax({
// type: "POST",
// url: '/Admin/DeleteLOB',
// data : {LOB_ID : lobmodel.LOB_ID},
// success: function (data)
// {
// alert("Record Deleted Successfully");
// GetLOB();//Refresh the Table
// },
// error: function (error)
// {
// }
// });
// };
// function GetLOB() {
// $.ajax({
// url: '/Admin/GetLOB',
// type: "POST",
// dataType: "json",
// success: function (returndata) {
// self.vm.LOBModel = returndata;
// ko.applyBindings(self.vm);
// alert("Hello");
// },
// error: function () {
// }
// });
// };
//}
//UNCOMMENTED SECTION DOES NOT BIND THE DATA TO HTML
function LOBViewModel() {
var self = this;
self.LOBModel = ko.observableArray([]);
GetLOB();
self.DeleteRecord = function (lobmodel) {
$.ajax({
type: "POST",
url: '/Admin/DeleteLOB',
data: { LOB_ID: lobmodel.LOB_ID },
success: function (data) {
alert("Record Deleted Successfully");
GetLOB();//Refresh the Table
},
error: function (error) {
}
});
};
function GetLOB() {
$.ajax({
url: '/Admin/GetLOB',
type: "POST",
dataType: "json",
success: function (returndata) {
self.LOBModel = returndata;
alert(self.LOBModel.length);
},
error: function () {
alert("eRROR GET LOB");
}
});
};
}
Details
My Json is in the following format
[0] = > { LOB_ID : 0 , LOB_Name : "data" LOB_description : "data" }
[1] => and so on
HTML File
<tbody data-bind="foreach: LOBModel">
<tr>
<td data-bind="text:LOB_ID"></td>
<td data-bind="text: LOB_Name"></td>
<td data-bind="text: LOB_Description"></td>
<td><button data-bind="click: $root.DeleteRec">Delete</button></td>
</tr>
</tbody>
My Question is
why is that
i have to use vm to bind the json into LOADModel so that it works, when i use self.LOBModel = ko.observableArray([]); the binding does not happen. i.e, my table does not load the data.
my Onlick does not get triggered in both the version of the code, I've tried self.DeleteRec, $root.DeleteRec and just DeleteRec as well. Though seems very obvious it just doesnot work.
Would the DeleteRec know which record i'm deleting. is lobmodel.LOB_ID correct way to use ?
To answer point by point:
(1) Your problem is in the GetLOB function, on this line:
self.LOBModel = returndata;
By doing that, you overwrite the self.LOBModel = ko.observableArray([]). What you should do instead is this:
self.LOBModel(returndata);
Then you should see the data in your table (if you have no other errors). The thing to remember here, is that if you make a variable observable, you always need to use the ()-syntax to read or write the underlying value. If you use = instead, you erase the observable functionality.
(2) the approach with '$root.DeleteRecord' is correct. 'self.DeleteRecord' would not work, and neither would just DeleteRecord. What would also work is '$parent.DeleteRecord'. The problem seems to be that you do 'DeleteRec' instead of 'DeleteRecord'.
(3) your approach is the right one. Deleted my others comments on this point, since Richard Dalton below me made a correct comment that invalidates what I typed here.
Edit: working Fiddle
http://jsfiddle.net/LFgUu/4/

Categories

Resources