jQuery rating plugin inside updatel panel - c#

I am using a jQuery rating plugin inside a asp:listview with in a asp:update panel. Below is the function which is being called on click of rating stars.
function DisplayRatings() {
$('DIV.ratingBar').each(function() {
var id = $(this).attr('id');
var count = $(this).attr('rel');
$('#' + id).raty({
showCancel: false,
readOnly: false,
showHalf: true,
start: count,
onClick: function(score) {
// I have to pass the score and ID to server side
}
});
});
}
Now I have to pass the 'score' and 'ID' to server side and call a method which rebinds the listview and updates the rating on the screen without screen refresh.
Please suggest how to go about this.( I can't use ajax toolkit rating as it doesn't support half star rating)

To pass data to the server, just store it in hidden form fields (in the UpdatePanel):
<asp:HiddenField id="score" runat="server" name="Score" ClientIDMode="Static" />
<asp:HiddenField id="id" runat="server" name="Score" ClientIDMode="Static" />
If you had a lot of data to pass back and forth, probably it would make sense just to use one hidden field and use serialization/deserialization to store it all there. Then in your onClick function, set the values of those fields, and initiate an async postback:
$('#score').val(score);
$('#id').val(id);
__doPostBack('UpdatePanelID', '')
This will cause an async update of your UpdatePanel, same as if a bound submit control was clicked by the user.
Note that if the jQuery control itself is in the UpdatePanel, you will have to reconfigure it after the async postback, since the effect is just as if the page had been reloaded as far as it is concerned. However, any javascript code which you may have run in $(document).ready() will not run after an async postback, since the whole page wasn't actually reloaded.
Ideally, keep the rating control outside the update panel, since you probably don't want it to change as a result of an event it initiated. If this isn't possible for some reason, or you just need a dynamic way to configure it the first time it is visible, then add a hook from the end of a page refresh:
// Page startup script - this adds a hook after an update panel is refreshed
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(onRefresh);
function onRefresh(sender, args) {
// You can try to check which panel was updated
var panelsUpdated = args.get_panelsUpdated();
var panelsCreated = args.get_panelsCreated();
// but usually it's easier to just track the state of your jquery stuff
if (my_jquery_thing_is_visible &&
my_indicator_that_it_has_already_been_configured===false) {
configureJqueryThing();
}
}

Solved it by using jQuery with AJAX.
aspx
function SaveRating(id, score) {
var params = '{linkID:"' + id + '",ratingVal:"' + score + '"}';
$.ajax({
type: "POST",
url: "page.aspx/UpdateRating",
data: params,
contentType: "application/json; charset=utf-8",
dataType: "json"
});
}
aspx.cs
[System.Web.Services.WebMethod]
public static void UpdateRating(string linkID, int ratingVal)
{
//code to update to db
}

Related

Knockout + MVC disable html button and change color after ajax call

I want to toggle disabled property for button after ajax call is successful.
The button is doing an ajax call to backend, and if returns as success, I have to disable that specific button.
I have n buttons, because they are generated in foreach loop for a table rows.
...
<td>
<button class="button primary" data-bind="click: $parent.sendDataToApi, attr: {'disabled' : passedIntegration }, style: { background: passedIntegration ? 'gray' : '' }">Send button</button>
</td>
...
My question is, am I need to put for each button id selector, or knockout somehow "knows" which button is ajax called, and only that button to disable and change color to gray?
my knockout.js file looks like:
define(['viewmodels/shell', 'durandal/services/logger', 'plugins/dialog', 'viewmodels/shell', 'toastr', 'knockout', 'kovalidationconfig', 'plugins/router', 'typeahead.bundle'],
function (shell, logger, dialog, shell, toastr, ko, kvc, router, typeahead) {
var vm = {
activate: activate,
shell: shell,
data: ko.observableArray([]),
close: function () {
$(window).off('popstate', vm.goBack);
$(window).off('resize', adjustModalPosition);
dialog.close(vm, 'cancel');
},
goBack: function () {
$(window).off('popstate', vm.goBack);
$(window).off('resize', adjustModalPosition);
dialog.close(vm, 'back');
},
editPreregisteredChildren: function () {
router.navigate("#/function/" + this.id);
},
sendDataToApi: function () {
$.ajax({
type: "POST",
url: rootUrl + 'home/sendData',
data: ko.toJSON({
requestId: this.id
}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
if (data.success === true) {
toastr.success(data.message)
// set that specific button disabled, remove hand-cursor, change background color to gray
} else {
toastr.error(data.message);
}
}
});
}
};
);
As you can see, I done the GET part, where on loading the rows, I setup buttons disabled/enabled, though I didnt figure it yet how to remove hand cursor on disabled button?
I stuck with other part, when I do ajax call, if call was successfull I also need to disable button.
Any suggestions how to do that?
there are a couple of ways to handle it. You didn't post which variable you are using in the forEach loop, but it will depend on that. I'm going to assume it's the "data" observableArray.
So if "data" is an array of objects, you can add an observable property to it, and then bind the disable to that property.
data = [{property: ..., disable: ko.observable()}]
Then you can pass in the array object you are on to the method by adding a parameter to the method as follows:
sendDataToApi: function (e) {
and change the binding to:
data-bind="click: $parent.sendDataToApi($data), disable: disable"
This will make "e" in the method the current iteration you are on, and then you can change set e.disable(true) when appropriate.

Ajax Request is sent more than once in a DataTable Delete action - ASP.NET, JQuery, Ajax

AJAX sent more than one request each time the function is called (ASP.NET MVC, Ajax and JQuery)
I have a webpage that has a table (using JQuery Datatable) and each row in the table has a delete button that holds the id of each row. The Id is used to send a Delete request to a Web API(in the same project) and, if the Id is correct, it will delete the row.
It works just fine if I use just once the button. However, if I click the button for one row (so it gets deleted), then, click to delete another row, I realized that the request is sent duplicated to the Web API, with both the Id of the previous call and the current call.
For that reason, the server will throw a NotFound error for the Id that had been deleted and, for the current id, it will delete just fine.
If I repeat with another button, it will send, then, three delete request.
I'm not an expert with Javascript (or ajax or jquery), so I couldn't figure out what I can do to solve it.
(I saw similar posts, but I couldn't find something that works in my case)
HTML to create each row:
// Note that it uses a data-customer-id to data attribute to hold the value
foreach (var customer in Model) {
<tr>
<td>
// ( unrelated code)
// DELETE BUTTON
<button type="button" class="btn btn-link js-delete"
data-customer-id="#customer.Id" data-toggle="tooltip"
data-placement="right" title="Using JQuery & AJAX">Delete
</button>
</td>
</tr>
}
Javascript:
<script>
$(document).ready(function() {
$("#customers").on("click", ".js-delete",function() {
//getting a reference for the button to be used when it's clicked
var button = $(this);
// call the modal (display the dialog box on the screen)
$("#deleteModal").modal();
// if the deleteConfirm button is clicked
$("#deleteConfirm").on("click", function () {
var urlLog = button.attr("data-customer-id");
$.ajax({
url: "/api/customers/" + button.attr("data-customer-id"),
method: "DELETE",
success: function () {
// case it's success, remove the row from the table
button.parents("tr").remove();
}
});
// hide de modal (dialog box)
$("#deleteModal").modal("hide");
});
});
});
</script>
Ouput in the Network tab in the browser
I was expecting that each click to a delete button would send only one request to the WebApi, not multiple requests.
That happens because you are attaching an event listener to your #deleteConfirm element every time you click on .js-delete.
Refactor and move your $("#deleteConfirm").on("click", function () ... function outside of the $("#customers").on("click", ".js-delete",function() ... block.
I modified my code following the suggestion above and separated both click functions.
Ps. If I kept both functions as they were in the beginning, one inside the other, I could use this code for the second click function it also works
$("#deleteConfirm").off().bind("click", function ()
In the end, the final script was:
$(document).ready(function() {
$("#customers").on("click", ".js-delete",function() {
//getting a reference for the button to be used when it's clicked
var button = $(this);
// STORE THE REFERENCE TO THE BUTTON
$("#deleteConfirm").data('ref', button);
// call the modal (display the dialog box on the screen)
$("#deleteModal").modal();
});
$("#deleteConfirm").on("click", function () {
//var button = $("#customers .js-delete");
// get the reference to the button
var button = $(this).data('ref');
$.ajax({
//url: "/api/customers/" + button.attr("data-customer-id"),
url: "/api/customers/" + button.attr("data-customer-id"),
method: "DELETE",
success: function () {
// case it's success, remove the row from the table
button.parents("tr").remove();
}
});
// hide de modal (dialog box)
$("#deleteModal").modal("hide");
});
});

Kendo UI input focus - After selection and Ajax call, DropdownList retains focus

We have a form with a dropdownlist and a mix of Telerik Kendo UI controls on it (as well as a Telerik Grid).
When the user makes a selection from the dropdown, an ajax call is made to an MVC controller action which sends back more data that will partially fill out the form. One of these fields is represented with a Kendo UI NumericTextBox.
The requirement is to set input focus on this NumericTextbox when the data returns.
However, this doesn't appear to be working in any scenario I try.
Here is how the numeric textbox is defined on the page:
#Html.Kendo().NumericTextBoxFor(model => model.ApplyFromPOA).Name("ApplyFromPOA").Step(0.01m).Min(0.00m).HtmlAttributes(new { #style = "width: 100%", #id = "ApplyFromPOA", #class = "defaultfocus" })
Here is the definition of the dropdownlist:
#Html.Kendo().DropDownList().Name("AddPaymentCustomer").BindTo(#Model.CustomerList).DataTextField("Name").DataValueField("ID").HtmlAttributes(new { style = "width: 100%; max-width: 300px;" }).Events(e => { e.Change("changeCustomerInAddPaymentWindow"); })
The changeCustomerInAddPaymentWindow function looks like this:
function changeCustomerInAddPaymentWindow (e) {
var dataItem = getSelectedDataItemFromDropdown(e);
var datagrid = $('#MyCustomerInvoiceResults').data('kendoGrid');
var dataSource = datagrid.dataSource;
if (null != dataItem) {
if (dataItem.ID == 0) {
// Clear out the form
clearOutForm();
}
else {
$.ajax({
url: "/Home/GetCustomerAndInvoices",
type: 'POST',
data: {
customerId: dataItem.ID
},
success: function (updatedModel) {
$("#ApplyFromPOA").val(updatedModel.ApplyFromPOA);
$("#poaAvailable").val(updatedModel.POAStringNoCommas);
$("#POAString").html(updatedModel.POAString);
$("#amount-left").html(updatedModel.POAString);
$.each(updatedModel.Invoices, function (index, item) {
dataSource.add(item);
});
dataSource.sync();
setTimeout(function () {
$("#ApplyFromPOA").select();
$("#ApplyFromPOA").focus();
$("#ApplyFromPOA").find("input").focus(0, function () { });
}, 200);
},
error: function () {
}
});
}
}
}
The relevant part is the attempt to set focus on the "ApplyFromPOA" control after the ajax call returns. This does not work. The dropdownlist retains focus.
I've also tried to use the 'sync' event of the grid to call a special function that will set the input focus on the "ApplyFromPOA" NumericTextBox. No love there either.
In every case, the DropdownList stubbornly retains input focus.
The problem is that the NumericTextbox will NOT update itself to the value that is set after the Ajax call until someone actually clicks into the field. When the AJAX call returns, we do this:
$("#ApplyFromPOA").val(updatedModel.ApplyFromPOA);
That sets the value correctly internally, but until someone sets the cursor on the control, it continues to display the previous value.
Ideally, we need to have the cursor input on that numeric text box anyway.
Thanks for your help.
Chad Lehman
20th Century Fox
Senior Dev/Architect
Enterprise IT team
The Kendo NumericTextBox actually does a really obnoxious thing and takes your existing <input> and sets it to display:none;, then makes a second <input> over top of it.
Behind the scenes in JS it copies the value back and forth between the inputs.
What you want to do is work with the widget instance instead of the input elements.
Inside your success callback, instead of using jQuery functions like .val() and .focus() replace it with:
success: function (updatedModel) {
// get Kendo widget instance
var applyFromPoaWidget = $("#ApplyFromPOA").data("kendoNumericTextBox");
// set new value
applyFromPoaWidget.value(updatedModel.ApplyFromPOA);
// set focus
applyFromPoaWidget.focus();
}

JQuery ajax post works only the first time

Edit (I have solved this):
I have figured this out - I was returning a string (integer.ToString("C")) in the JSON data which I then placed into my textbox. Upon clicking the submit button, it was trying to parse the currency (now: "£2.99") into an integer (currentAmount is an integer in my bid object), which of course became 0, which resulted in my bid form not being able to serialise this data.
Currently I have an Ajax request through JQuery which performs a postback on my BID controller method. The method returns some JSON which lets me update my HTML with current values, such as Current Price, Bid Count, and the Next Recommended Bid Price.
My problem is, once I click the submit button, the ajax makes the post and correctly returns the data I expect. However, when I click the Submit button a second time, the bid passed pass through to my controller from my View doesn't have my form data (amount is now 0, when I can see it isn't on the page)
Why is this? I am using entity framework to save my auction and bid.
Here is my code:
Controller BID Post
[HttpPost]
public ActionResult Bid(Bid bid)
{
var db = new AuctionsDataContext();
var auction = db.Auctions.Find(bid.AuctionId);
bid.Username = User.Identity.Name;
auction.Bids.Add(bid);
auction.CurrentPrice = bid.Amount;
db.SaveChanges();
return Json(new
{
CurrentPrice = bid.Amount.ToString("C"),
BidCount = auction.BidCount,
Number = (bid.Amount + 1).ToString("C")
});
}
My BID form on Auction.cshtml
<p>
#using (Html.BeginForm("Bid", "Auctions"))
{
var lowestBidAmount = auction.CurrentPrice.GetValueOrDefault(auction.StartPrice) + 1;
<span>
Bid: $#Html.TextBox("amount", lowestBidAmount)
#Html.ValidationMessage("amount")
</span>
#Html.Hidden("auctionId", auction.Id)
<input class="post-bid" type="submit" value="Bid" />
}
</p>
My Ajax script
#section Scripts{
<script type="text/javascript">
$(function () {
$('.post-bid').on("click", function () {
var form = $(this).parent("form");
$.ajax({
type: "POST",
url: form.attr('action'),
data: form.serialize()
})
.success(function (data) {
var template = $('#current-price-template').clone().html();
var html = template
.replace('{{CurrentPrice}}', data.CurrentPrice)
.replace('{{BidCount}}', data.BidCount);
$('.current-price').replaceWith(html);
$('#amount').val(data.Number);
})
.error(function () {
alert("Your big has been rejected");
});
return false;
});
});
</script>
I can't see the content of the template but my guess would be that you are replacing the content to which to click event is attached and so when you replace the dom element you lose the click event binding. This type of binding is called directly bound.
To achieve the type of functionality you want you need to use the delegated style of binding where the click event handler is bound to a parent element or higher and a selector parameter in the binding call identifies which elements to process the click event for. This type of event binding is called delegated. When the content is replaced the handler remains and is available to handle the events from the child elements identified by the selector.
In your case something like.
form.on('click', '.post-bid',eventHandler);
For a more detailed description please the documentation for the jquery .on statement
http://api.jquery.com/on/
I have figured this out - I was returning a string (integer.ToString("C")) in the JSON data which I then placed into my textbox. Upon clicking the submit button, it was trying to parse the currency (now: "£2.99") into an integer (currentAmount is an integer in my bid object), which of course became 0, which resulted in my bid form not being able to serialise this data.

Button click event not firing from javascript

I need to do a postback and save the data in the screen to session when the screen is closed, for this i am using the onBeforeUnload event, and placed a hidden button in the screen. In the on before unload event I am calling the click event to call the button server event. But the event is not firing. Is anything I am missing here.
<asp:Button Style="display: none" runat="server" ID="btnHidUpdate" OnClick="btnHidUpdate_Click" />
<script type="text/javascript">
$(document).ready(function () {
window.onbeforeunload = updateSessionBeforeUnload;
});
</script>
In .js file:
function updateSessionBeforeUnload() {
var hidUpdate = $('[id$="btnHidUpdate"]')[0];
hidUpdate.click();
}
In .cs code behind:
protected void btnHidUpdate_Click(object sender, EventArgs e)
{
UpdateSession();
}
The problem is that the page loads the next page before it can execute the button click.
Use the Jquery Unload event e.g.
$(function(){
$(window).unload(function(){
// put synchronous code here to persist what you need.
});
});
You can use an Ajax event like Yuriy says however you must set async to false like this:
$.ajax({
type: "POST",
url: "Url/To/Persistance",
dataType: "json",
data : { "data" : "to be persisted"},
async: false
});
EDIT
I would avoid the click event all together and do something like this:
$(function(){
$(window).unload(function(event){
var hidUpdate = $('[id$="btnHidUpdate"]')[0];
__doPostBack(hidUpdate.attr('id'),'');
});
});
However if you must click the button try this
$(function(){
$(window).unload(function(event){
var hidUpdate = $('[id$="btnHidUpdate"]')[0];
hidUpdate.click()
alert(
"Default: " + event.isDefaultPrevented() + "\n" +
"ImedPropStopped: " + event.isImmediatePropagationStopped() + "\n" +
"PropStopped: " + event.isPropagationStopped()
);
});
});
And tell us what the alert says ?
I think the other suggestions here should work fine. I have another suggestion which you can try, and is to use GetPostBackEventReference.
You can see details about it here:
http://msdn.microsoft.com/en-us/library/aa720417(v=vs.71).aspx
You can use jquery trigger("click") function which will call the click event on the button.
In my opinion the problem is that onbeforeunload event handler intended to ask user for confirmation when he want to leave a page. And since updateSessionBeforeUnload method doesn't returns any question string, unloading process continues immediately after this method leaves.
If you can make UpdateSession method static you can call it asynchronously with async jQuery.ajax method call:
<script type="text/javascript">
window.onbeforeunload = foobar;
function foobar() {
$.ajax({
type: "POST",
url: "WebForm2.aspx/UpdateSession",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true
});
}
</script>
[WebMethod]
public static void UpdateSession()
{
}

Categories

Resources