Increment Value on Model using Ajax and Razor - c#

I'm looping through a collection on my model using Razor to display it. As an example:
#foreach(var item in myCollection)
{
<span id='item-#item.Id'>#item.Quantity</span>
<button type='button' onclick='updateQuantity(#item.Quantity+1);'>Add One</button>
}
In this example, updateQuantity performs an AJAX request, gets the new quantity back, and updates item-#item.Id with the new quantity. However, because #item.Quantity is pulled from the model (passed in via the page's GET method, #item.Quantity is never updated with the new value until the page is reloaded.
My question is: How can I make sure I'm always using the latest value, without having to reload the page?

Change the button inside your foreach loop like this:
#foreach(var item in myCollection)
{
<span id='item-#item.Id'>#item.Quantity</span>
<button id='updateButton' type='button'>Add One</button>
}
And, add this script to your View:
<script>
$("#updateButton").click(function() {
var quantity = $("#item-#item.Id").text();
updateQuantity(quantity);
})
</script>
And, in your updateQuantity() function, update the text inside the span after getting it back through Ajax.

Related

How to pass an ID parameter to Blazorise modal on button click, from one component to another?

I'm new and trying to formulate this as best as I can. There's so much new concepts to get a hold of! Please tell me if I'm unclear.
I'm making a Todo-app as an exercise. On page load I get todo items from the database and iterate them in a foreach-loop, each todo is assigned an X-button for removal. This was easy, but for modifying a todo text I want an update button that brings up Blazorise's modal popup, to use it's input field.
My problem is that I don't get how to pass each todo item's id into this modal, for each button that is. For the remove button I could use the foreach loop's "todoItem.Id" variable, but as the Blazorise modal is another component I can't.
Here's how my Index page looks:
#page "/"
#using TodoApp.App.Components
<section class="todo-container">
#if (TodoItems != null)
{
#foreach (var todoItem in TodoItems)
{
if (todoItem.IsDone == false)
{
<div class="todo-item">
<p>#todoItem.Text</p>
<UpdatePopup OnTodoItemUpdated="UpdateAndLoad"></UpdatePopup>
<Button class="remove-btn" Clicked="(() => RemoveTodoItem(todoItem.Id))">X</Button>
</div>
}
}
}
</section>
<Popup OnTodoItemAdded="UpdateAndLoad"></Popup>
This button is inside the modal itself: <Button Clicked="#ShowModal">...</Button>, and I would've wanted to do the same thing as with the remove button, adding something like () => UpdateTodoItem(todoItem.Id).
How to get the ID from each item in the Index component and add this to each button in the Modal component?
There are multiple problems with your solution. First, you're creating a modal for each todo item (UpdatePopup) which is very inefficient. You should instead create just one update modal and use it for all the items.
#page "/"
#using TodoApp.App.Components
<section class="todo-container">
#if (TodoItems != null)
{
#foreach (var todoItem in TodoItems)
{
if (todoItem.IsDone == false)
{
<div class="todo-item">
<p>#todoItem.Text</p>
<Button class="update-btn" Clicked="(() => updatePopupRef.Show(todoItem))">Edit</Button>
<Button class="remove-btn" Clicked="(() => RemoveTodoItem(todoItem.Id))">X</Button>
</div>
}
}
}
</section>
<UpdatePopup #ref="#updatePopupRef" OnTodoItemUpdated="UpdateAndLoad" />
<Popup OnTodoItemAdded="UpdateAndLoad" />
#code{
UpdatePopup updatePopupRef;
}
And then in UpdatePopup you have something like this:
void Show(TodoItem item)
{
this.Item = item; // use this to bind item values to input fields
modalRef.Show(); // you also need to have modalRef set with #ref attribute
}
and in razor
<TextEdit #bind-Text="#Item.Name" />
PS. I haven't tested this code but you should have an overall idea :)

Render part of page on dropdown selection part 2

This is a follow on to similar question but taking suggestions into account.
Render part of page on dropdown selection
I have a chart on my main view which I would like to update partially when a dropdown selects different values.
The page renders correctly the first time, but when I select a new value in the dropdown, then I think the .submit script is failing in the script .submit() because when I put a break on window.submitAjaxForm it is never reached.
_PnlChart.cshtml
<img src="#Url.Action("CreateTraderPnlChart3")" width="600" height="600" align="middle" vspace="50" />
My mainview Index.cshtml:
<div class="w3-half">
<div id="ExportDiv">
#{ Html.RenderPartial("_PnlChart");}
</div>
#using (Ajax.BeginForm("GetEnvironment",
new RouteValueDictionary { { "Environment", "" } }, new AjaxOptions() { UpdateTargetId = "ExportDiv" }, new { id = "ajaxForm" } ))
{
#Html.DropDownList("PeriodSelection",
new SelectList((string[])Session["Periods"]),
(string)Session["Period"],
new
{ onchange = "submitAjaxForm()" })
}
</script>
<script type="text/javascript">
$('form#ajaxForm').submit(function(event) {
eval($(this).attr('onsubmit')); return false;
});
window.submitAjaxForm = function(){
$('form#ajaxForm').submit();
}
</script>
</div>
My controller:
public ActionResult PeriodSelection(string dropdownlistReturnValue) // dont know what dropdownlistReturnValue is doing?
{
Session["Period"] = dropdownlistReturnValue;
return PartialView("~/Views/Employee/_PnlChart.cshtml");
}
This line in your code,
eval($(this).attr('onsubmit')); return false;
I am not sure what you were intending to do here. But from your question, i assume you wanted to do a form submission. But that line will not submit the form. The expression $(this).attr('onsubmit') is going to return undefined as your form does not have an onsubmit attribute defined.
But you already have the form submit code in your other method (submitAjaxForm). So if you simply remove the $('form#ajaxForm').submit handler (apparently it does not do anything useful), your code will work. When you change the dropdown, it will make an ajax form submission.
But your form action is set to GetEnvironment action method. That means your ajax form submission will be to that action method. In your question you have a different action method which returns the updated chart content. It does not makes sense!
I personally prefer to write handwritten ajax calls instead of relying on the ajax action helper methods. The below is the code i would probably use (Except the dropdownlist code. read further)
<div id="ExportDiv">
#{ Html.RenderPartial("_PnlChart");}
</div>
#Html.DropDownList("PeriodSelection",
new SelectList((string[])Session["Periods"]),
(string)Session["Period"], new
{ data_charturl = Url.Action("PeriodSelection","Home")})
Now listen to the change event of the SELECT element.
$(function(){
$("#PeriodSelection").change(function(){
var v = $(this).val();
var url=$(this).data("charturl")+'?dropdownlistReturnValue='+v;
$("#ExportDiv").load(url);
});
});
You should consider using the a view model to pass the Dropdownlist data. Why not use the DropDownListFor helper method ? It looks much clean, Mixing a lot of C# code (See all the session casting and all.) makes it kind of dirty IMHO.

How to filter data from dynamically generated list?

Currently I am working on one web application in asp.net.
Application received data from web-service in json format. Requirement is to develop controls dynamically, I did it using html controls. I dynamically created list of label & stored values in it. Now I want to add filter on the top of that list so that it can filter data based on vales entered in the textbox.
I want something like below textbox list of data like item1, item2 and so on, based on value entered in textbox. I need to filter data.
How I can achieve this?I tried to use list.js but it didn't work.
<% foreach (var item in (List<string>)Session["list"])
{
%>
<%--<li><label onclick="redirect('<%:item %>')"><%: item %></label><br/></li>--%>
<li><%:item %></li>
<% } %>
Add texbox with onkeyup event handler, set some id to ul e.g. id="list"
<input type="text" onkeyup="filter(this)" />
<ul id="list">
<li>a</li>
<li>abc</li>
<li>bcd</li>
<li>abc</li>
</ul>
Add the following script (source) and a reference to jquery
<script>
function filter(element) {
var value = $(element).val();
$("#list > li").each(function() {
if ($(this).text().search(value) > -1) {
$(this).show();
}
else {
$(this).hide();
}
});
}
</script>
Demo: http://jsbin.com/hahodetu/1/edit?html,output

Calling Javascript functions from href defined in Razor file

So I have this function cart.remove(itemid), that removes an item from the shopping cart using an ajax call. The cart object is defined in its own javascript file and its functions are accessible and the remove() function works properly to remove items as intended. Upon clicking the link below, an alert pops up, confirming if you really want to remove the item. If yes, it removes the item from the shopping cart.
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
<div><a title="Remove item from cart" href="javascript:cart.remove(#(item.ItemID));">Remove Item</a></div>
}
}
Now, due to complexity of the different types of items in the shopping cart, for a more user friendly UI, I need the confirm-remove-item alert text to be different, depending on the item that is clicked. I have a function defined in the model, GetRemoveItemAlertText(int itemid) that returns the appropriate text. I wrap that text in a json object so that the text isn't visible as one of the remove() function's parameters, when someone hovers over the link, in the browser statusbar.
The javascript remove() function has been redefined to remove(itemid, alerttext) to display the custom remove text, instead of the same text every time. No other changes to that function; it still displays an alert and removes the item if the user clicks yes to the confirmation. Here is my attempt at removing the item with the custom alert text:
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
var alert = Model.GetRemoveItemAlertText(item.ItemID);
<script type="text/javascript">
function removeItem_#(item.ItemID)() {
var bodytext = "#UriEscapeDataString(alertText)";
var alerttext = {
bodytext: bodytext
};
cart.remove(#(item.ItemID), alerttext);
}
</script>
<div><a title="Remove item from cart" href="javascript:cart.removeItem_#(item.ItemID)();">Remove Item</a></div>
}
}
Since the javascript function is defined inside a loop, the name needs to be different each time, hence the itemid in the function name. It should grab the custom remove-item text and then call cart.remove(), just like it was previously being done inside the href definition. The problem is that this function removeItem_#(item.ItemId)() is not being called. Even if I just put an alert() or console.log() inside the function, the code never fires. Is there anyway to accomplish this? I've also tried calling that function by using a click listener bound to a class that is on a <span>' or`. Any suggestions? I can clearly see, by viewing the page source, that each of the cart's current items have their own remove-item function defined, but for some reason, the code isn't reachable.
Try this on for size, of course all of this can be done MUCH easier with JQuery if you would like a much better solution:
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
<div><a title="Remove item from cart" id="#item.ItemID" hreaf="javascript:return RemoveItem(#item.ItemID);" data-message="#Model.GetRemoveItemAlertText(item.ItemID)">Remove Item</a></div>
}
}
<script>
function RemoveItem(itemId)
{
var element = document.getElementById(itemId.toString());
var alerttext = element.getAttribute('data-message');
return cart.remove(#(item.ItemID), alerttext);
}
</script>
Much better if we can use JQuery:
#if (Model.Count > 0)
{
foreach (var item in Model.Items)
{
<div><a title="Remove item from cart" href="#" class="cart-item" data-itemid="#item.ItemID" data-message="#Model.GetRemoveItemAlertText(item.ItemID)">Remove Item</a></div>
}
}
<script>
$(document).ready(function(){
$('.cart-item').click(function(e){
e.stopProgagation();
cart.remove($(this).data('itemid'), $(this).data('message'));
});
});
</script>

Value passed NULL from a View to another in ASP MVC 3

I am developing an ASP .Net MVC 3 application using C# and SQL Server 2005.
I am using also Entity Framework and Code First Method.
In a view Index, I have a DropDownList Gamme. I define its item selected in my view, like this :
public string SelectedProfile_Ga { get; set; }
In this view, I have a button Appliquerthat took me to another view Application.
<input type="button" value="Appliquer" id="appliquer" onclick="window.location = 'ProfileGa/Application'"/>
In the view Application, I have a button submit Appliquer.
<input type="submit" value="Appliquer" id="appl" />
When I click on Appliquer, I want save the value selected in my DropDownList Gamme in my base.
The problem is that this value is passed NULL when i change the view (exit page Index and open Application).
I find that with Debugging.
The Controller action :
[HttpPost]
public ActionResult app(FlowViewModel model)
{
Famille fam = new Famille();
fam.ID_Gamme = model.SelectedProfile_Ga;
db.Familles.Add(fam);
db.SaveChanges();
return RedirectToAction("Application");
}
Note :
I didn't forget this in the Application:
<% using (Html.BeginForm("app", "ProfileGa")) { %>
ProfileGa is the name of my controller.
For starters, your dropdown is in the Index view, and the selection is happening there. Then you're redirecting to ProfileGa/Application and leaving this information behind.
I would change this button:
<input type="button" value="Appliquer" .. etc
to a <submit>, and wrap the code with the dropdown in one of these:
using (Html.BeginForm("Application", "ProfileGa")) {
and add a Post version of Application
[HttpPost]
public ActionResult Application(FlowViewModel model)
{
// Do whatever
return View(model);
}
Then when you get to the Application view, it should still have the same information as it left Index with.
To check this is working, put a breakpoint at return View(model); and look at the model's contents.
However, posting null from the view probably means that something is wrong inside your <% using (Html.BeginForm("app", "ProfileGa")) { %> statement, so if the above doesn't do anything, post the code from your `Application' view.

Categories