I am trying to have this AJAX code working. When I run the WebStore it display a list of categories which If I clicked on 1 category, I can then select a product. The product show up and I can added to the cart. After it's been added to the cart, I clicked on Remove from the Cart and nothing is refreshing. I based my solution on the MVC Music Store and I also read the old solution was not updated for this Ajax Part. I found this instead and I guess I am missing something.
I noticed an URL change localhost:49523/Panier#. Any idea why a # is there ?
Thanks
index.cshtml from panier
#model Tp1WebStore3.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="/Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function handleUpdate(context) {
// Load and deserialize the returned JSON data
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// Update the page elements
$('#row-' + data.DeleteId).fadeOut('slow');
$('#cart-status').text('Cart (' + data.CartCount + ')');
$('#update-message').text(data.Message);
$('#cart-total').text(data.CartTotal);
}
</script>
<h3>
<em>Details</em> du panier:
</h3>
<p class="button">
#Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Produit
</th>
<th>
Prix (unitaire)
</th>
<th>
Quantite
</th>
<th></th>
</tr>
#foreach (var item in Model.CartItems)
{
<tr id="row-#item.ProduitId">
<td>
#Html.ActionLink(item.Produit.Description,"Details", "Panier", new { id =
item.ProduitId }, null)
</td>
<td>
#item.Produit.Prix
</td>
<td id="item-count-#item.ProduitId">
#item.Quantite
</td>
<td>
Remove from Cart
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
#Model.CartTotal
</td>
</tr>
</table>
PanierController.cs
// AJAX: /ShoppingCart/RemoveFromCart/5
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
string produitDescription = dbProduit.Paniers
.Single(item => item.PanierId == id).Produit.Description;
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(produitDescription) +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
Modify Index.cshtml
#model Tp1WebStore3.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$('.RemoveLink').click(function () {
$.ajax({
url: '/Panier/RemoveFromCart',
data: { id: $(this).data('id') },
cache: false,
success: function (result) {
$('#row-' + result.DeleteId).fadeOut('slow');
$('#cart-status').text('Cart (' + result.CartCount + ')');
$('#update-message').text(result.Message);
$('#cart-total').text(result.CartTotal);
}
});
return false;
});
});
</script>
I am adding also the
ShoppingCart.cs
public int RemoveFromCart(int id)
{
// Get the cart
var cartItem = db.Paniers.Single(
cart => cart.CartId == ShoppingCartId
&& cart.ProduitId == id);
int itemCount = 0;
if (cartItem != null)
{
if (cartItem.Quantite > 1)
{
cartItem.Quantite--;
itemCount = cartItem.Quantite;
}
else
{
db.Paniers.Remove(cartItem);
}
// Save changes
db.SaveChanges();
}
return itemCount;
I got more information. When I ran Chrome with PF12 and Network, I saw a page not found
In my Panier I got this key (newly created) for the CartId : dbfac4de-ae5e-4fbf-a44a-f6bb8ee3f2fc
In Chrome it complaining about this:
RemoveFromCart?id=dbfac4de-ae5e-4fbf-a44a-f6bb8ee3f2fc&_=1394045298037
/Panier
I don't understand the next part of the key (concatenation) &_=1394045298037
My ProduitId are define like this for the key: 3
Can anyone explain this to me ?
You have a remove anchor:
Remove from Cart
and some javascript handleUpdate function which is absolutely never called:
<script type="text/javascript">
function handleUpdate(context) {
// Load and deserialize the returned JSON data
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// Update the page elements
$('#row-' + data.DeleteId).fadeOut('slow');
$('#cart-status').text('Cart (' + data.CartCount + ')');
$('#update-message').text(data.Message);
$('#cart-total').text(data.CartTotal);
}
</script>
You also seem to be using an extremely outdated version of jquery:
<script src="/Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
and a dinosaurly old, stone age outdated and deprecated Microsoft AJAX scripts:
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
So start by removing the dinosaurly old scripts from your ASP.NET MVC application as well as the handleUpdate function which is absolutely never used.
Then you could write some jQuery ajax function that will subscribe to the click event of your anchor and perform an AJAX request:
<script type="text/javascript">
$(function() {
$('.RemoveLink').click(function() {
$.ajax({
url: '/ShoppingCart/RemoveFromCart',
data: { id: $(this).data('id') },
cache: false,
success: function(result) {
$('#row-' + result.DeleteId).fadeOut('slow');
$('#cart-status').text('Cart (' + result.CartCount + ')');
$('#update-message').text(result.Message);
$('#cart-total').text(result.CartTotal);
}
});
return false;
});
});
</script>
Also you should learn how to debug your AJAX calls in your web browser. All modern web browsers (such as Google Chrome) come with javascript debugging tools that would help you debug and analyze such problems. So don't hesitate to fire your debugging toolbar using F12 and look at the Network tab. It will provide you useful information about all network requests (including AJAX) that the browser is making. The Console tab will show you any potential javascript errors you might be having in your code. So instead of saying on StackOverflow that nothing happens when you click on some anchor, next time use your javascript debugging toolbar to analyze what happens under the covers.
Related
I tried to add autocomplete or suggestion functionality in search box of view, as when some one enter any character, any word containing that character shows as suggestion, but this not works. I followed different tutorials but not able to solve it. Please take a look and give me the direction.
Thnx in advance.
Controller
public async Task<IActionResult> dashboard(string sortOrder, string SearchString)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(SearchString))
{
movies = movies.Where(s => s.MovieName.Contains(SearchString));
}
switch (sortOrder)
{
case "name_desc":
movies = movies.OrderByDescending(s => s.MovieName);
break;
default:
movies = movies.OrderBy(s => s.MovieName);
break;
}
return View(await movies.AsNoTracking().ToListAsync());
}
public JsonResult AutoComplete(string prefix)
{
var customers = (from movie in this._context.Movie
where movie.MovieName.StartsWith(prefix)
select new
{
label = movie.MovieName,
val = movie.Id
}).ToList();
return Json(customers);
}
dashboard.cshtml
#model IEnumerable<WebApplication1.Models.Movie>
#{
ViewData["Title"] = "dashboard";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Dashboard</h1>
#using (Html.BeginForm())
{
<p>
Find by Movie Name: #Html.TextBox("SearchString")
<input type="hidden" id="hfCustomer" name="Id" />
<input type="submit" value="Search" />
</p>
}
<table class="table">
<thead>
<tr>
<th>
<a asp-action="dashboard" asp-route-sortOrder="#ViewData["NameSortParm"]">#Html.DisplayNameFor(model => model.MovieName)</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.MovieName)
</td>
</tr>
}
</tbody>
</table>
<script type="text/javascript">
$(function () {
$("#txtMovie").autocomplete({
source: function (request, response) {
$.ajax({
url: '/Movies/AutoComplete/',
data: { "prefix": request.term },
type: "POST",
success: function (data) {
response($.map(data, function (item) {
return item;
}))
},
error: function (response) {
alert(response.responseText);
},
failure: function (response) {
alert(response.responseText);
}
});
},
select: function (e, i) {
$("#hfCustomer").val(i.item.val);
},
minLength: 1
});
});
</script>
I tried to add autocomplete or suggestion functionality in search box of view, as when some one enter any character, any word containing that character shows as suggestion, but this not works.
Find by Movie Name: #Html.TextBox("SearchString")
If you check the html source code of above TextBox in your browser, you would find it is rendered as below.
The value of id attribute is "SearchString", not "txtMovie". You can try to modify the code to use $("#SearchString") selector, like below.
$("#SearchString").autocomplete({
//...
//code logic here
//...
Test result with testing data
Note: please make sure you add references to required jquery libraries.
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
For example: I have to two roles in my application.
1.Administrator // Can perform all CRUD operations on data.
2.Customer // Can only Read the existing data.
In case of returning view to the User according to there role ?
Now I have a choice that create two separate views according to roles.
Let see some Code.
public ActionResult Index()
{
var customers = _dbContext.Customers.Include(c => c.Type).ToList();
if (User.IsInRole(userRole.IsAdministator))
{
return View("Admin_List_View", customers);
} else
{
return View("Customer_ReadOnlyList_View" , customers);
}
}
In the above code.I have two view.
1.Admin_List_View // This view contains all the Data along with Add,Delete,Update,Edit options.
2.Customer_ReadOnly_View // This view will only contains Readonly list.
So my question is that:
In case of simple view i have to follow this approach by writing a separate view for a target roles.
But as it Possible to have a single view and assign the specific section of that to specfic role ?
Note:
I am asking this question is that...In case of complex view that i don't have a choice to create another view from scratch for a particular role. So i am wondering that there is any way to play with the existing view.
For example:
I have to roles.
Admin & customer
and
i have one view.
How to manage that one view for these to roles?
Possible to have a single view and assign the specific section of that to specfic role ?
Yes. You can achieve this with Razor syntax which allows C# in your HTML. Prefix your C# statements with "#". See here.
In your View:
<button>Do Regular User Stuff</button>
#if(User.IsInRole("Admin") {
<button>Do Admin Stuff</button>
}
More Detailed Answer:
public ActionResult Index()
{
var customers = _dbContext.Customers.Include(c => c.Type).ToList();
if (User.IsInRole(userRole.IsAdministator))
{
return View("Admin_List_View", customers);
} else
{
return View("Customer_ReadOnlyList_View" , customers);
}
}
In the above example.
when have two roles and both roles have specfic view.
1.One way is:
to create two view for separate role
for the above example: i had created two views
1.Admin_List_View
2.Customer_ReadOnlyList
2.2nd ways is:
to create sample view and assign html contents based on a user role.
For example:
I have to roles:
again i will say that:
1.AdminList
2.CustomerList.
and now i have only one view:
index.cshtml
index.cshmtl
#model IEnumerable<Vidly.Models.Customer>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 id="heading">Customers</h2>
// This Button is accessible to only admin.
#Html.ActionLink("Add New Customer" , "Add" , "Customer" )
#if (Model.Count() == 0)
{
<p>No Customer is found.</p>
}
else
{
<table id="customers" class="table table-bordered table-hover">
<thead>
<tr>
<th>Full Name</th>
<th>Email Address</th>
<th>Physical Addrses</th>
<th>Type</th>
<th>Actions</th> // This Column will be only accessible to
admin role.
}
</tr>
</thead>
#foreach (var item in Model)
{
<tbody>
<tr>
<td>#item.FullName</td>
<td>#item.EmailAddress</td>
<td>#item.PhysicalAddress</td>
<td>#item.Type.TypeName</td>
// These Button will be only accessible to Admin
// This is the Edit Button.
<td><button data-customer-id="#item.Id" class="btn btn-link js-delete">Edit</button></td>
// This is the Delete Button.
<td><button data-customer-id="#item.Id" class="btn btn-link js-delete">Delete</button></td>
</tr>
</tbody>
}
</table>
}
#section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$("#customers").DataTable();
$("#customers").on("click", ".js-delete", function () {
var button = $(this);
var result = confirm("Are you sure you want to delete this customer?");
function (result) {
if (result) {
$.ajax({
url: "/api/customers/" + button.attr("data-customer-id"),
method: "Delete",
success: function () {
button.parents("tr").remove();
},
error: function (xhr) {
alert("Something goes wrong." + " " + " Error Details " + xhr.status);
}
});
}
});
});
});
</script>
}
So This the entire view.
Now assigning specfic content to specfic Role:
#model IEnumerable<Vidly.Models.Customer>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 id="heading">Customers</h2>
#if(User.IsRole("Admin")) // Checking that if the LoggedIn User is Admin or Not? if The User is Admin Dispay this "Add New Customer Link" Otherwise don't display it.
{
// This Button is accessible to only admin.
#Html.ActionLink("Add New Customer" , "Add" , "Customer" )
}
#if (Model.Count() == 0)
{
<p>No Customer is found.</p>
}
else
{
<table id="customers" class="table table-bordered table-hover">
<thead>
<tr>
<th>Full Name</th>
<th>Email Address</th>
<th>Physical Addrses</th>
<th>Type</th>
#if(User.IsRole("Admin")) // Again Checking That the User is Admin or not? if the User admin Display the table Header otherwise don't display it.
{
<th>Actions</th> // This Column will be only accessible to admin role.
}
</tr>
</thead>
#foreach (var item in Model)
{
<tbody>
<tr>
<td>#item.FullName</td>
<td>#item.EmailAddress</td>
<td>#item.PhysicalAddress</td>
<td>#item.Type.TypeName</td>
#if(User.IsRole("Admin")) // Checking that the LoggedIn User is Admin or Not. If the User is Admin the Display these buttons otherwise don't Display it.
{
// These Button will be only accessible to Admin
// This is the Edit Button.
<td><button data-customer-id="#item.Id" class="btn btn-link
js-delete">Edit</button></td>
// This is the Delete Button.
<td><button data-customer-id="#item.Id" class="btn btn-link
js-delete">Delete</button></td>
}
</tr>
</tbody>
}
</table>
}
#section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$("#customers").DataTable();
$("#customers").on("click", ".js-delete", function () {
var button = $(this);
var result = confirm("Are you sure you want to delete this customer?");
function (result) {
if (result) {
$.ajax({
url: "/api/customers/" + button.attr("data-customer-id"),
method: "Delete",
success: function () {
button.parents("tr").remove();
},
error: function (xhr) {
alert("Something goes wrong." + " " + " Error Details " + xhr.status);
}
});
}
});
});
});
</script>
}
I have a page which is being populated with a list of checkboxes for each record in the database. The user can select as many checkboxes as they want and the system should save their responses. I'm having a hard time getting my array of selected checkboxes to pass through to my Controller.
When i run my code and click the submit button i get a Maximum call stack size exceeded and i'm not sure how to solve that.
Image of the browser console error message: http://imgur.com/a/BnKLL
.cshtml:
#{
ViewBag.Title = "Subject";
}
<head>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>
<h2>Explore Subjects</h2>
<div>
<button id="SubmitButton">Save Changes</button>
<div style="border-bottom:solid">
<h4>Your Followed Subjects</h4>
<div id="FollowedSubjects">
#foreach (var subject in Model.FollowedSubjects)
{
<input type="checkbox" name="SubjectCheckBox" checked="checked" value=#subject.SubjectId>#subject.SubjectDetail.Subject<br>
}
</div>
</div>
<div id="AllSubjects">
<br />
<h4>More Subjects to Follow</h4>
<p>Ordered by number of bills with subject</p>
#foreach(var subject in Model.AllSubjects)
{
<div class="subjectDisp">
<input type="checkbox" name="SubjectCheckBox" value=#subject.Subject.SubjectId>#subject.Subject.Subject (#subject.Count) <br>
</div>
}
</div>
</div>
<script>
$(document).ready(function () {
$('#SubmitButton').click(function () {
var checkboxes = document.getElementsByName("SubjectCheckBox");
var checked = [];
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
checked.push(checkboxes[i]);
}
}
$.ajax({
url: '#Url.Action("FollowSubjects", "Home")',
type: 'POST',
data: { Parameters: checked },
success: function (result) {
alert("success");
},
error: function (result) {
alert("error");
}
});
alert("there")
});
});
</script>
My controller funtion that im trying to call.
[HttpPost]
public ActionResult FollowSubjects(int[] Parameters)
{
int i = 0;
return View();
}
Eventually i will have this hit the database but for now i just put a breakpoint at int i = 0; to see what gets passed to the function.
You can send it as an array of string and convert them to int at server side or Stringify it and send
var checked=""
$(checkboxes).each(function () {
checked += this + ',';
i++;
ajax --> data: { Parameters: checked },
[HttpPost]
public ActionResult FollowSubjects(string Parameters)
{
// Do your task
return View();
}
I need to have a DropDownList or equivalent in ASP.NET MVC in a View, which is populated with a bunch of entries from a database.
When selected, the DropDownList should produce the List as usual, with the exception that the user can enter text into it, at which point the items in the DropDownList will be filtered based on the entered text.
The user should however still only be able to choose one of the options in the list.
It could be any other control, but preferably NOT a 3rd party thing.
It is possible by writing some jQuery code. But it is already available and it is open source, widely used
Use jQuery chosen and configure like below
$(".select").chosen();
I found a decent method that works.
The only problem with this is that it requires 2 separate controls (DropDownList and TextBox), but other than that, works beautifully.
HTML Code (declaration of controls) is:
<table>
<tr>
<td>
<div>
<%: Html.Label("Search Filter:")%>
</div>
</td>
<td>
<div>
<%: Html.TextBox("textBoxForFilterInput")%>
</div>
</td>
</tr>
<tr>
<td>
<div>
<%: Html.Label("The List")%>
</div>
</td>
<td>
<div>
<%: Html.DropDownList("listOfOptions")%>
</div>
</td>
</tr>
</table>
The JavaScript code is:
$(function () {
var opts = $('#listOfOptions option').map(function () {
return [[this.value, $(this).text()]];
});
$('#textBoxForFilterInput').keyup(function () {
var rxp = new RegExp($('#textBoxForFilterInput').val(), 'i');
var optlist = $('#listOfOptions').empty();
opts.each(function () {
if (rxp.test(this[1])) {
optlist.append($('<option/>').attr('value', this[0]).text(this[1]));
}
});
});
});
Then just populate #listOfOptions and then you should be good to go.
Alternatively, you could hook it up to a predefined list/array or fetch it from a database like I do.
This works like a charm, very simple and super fast.
Thanks to DMI for sending me on the right path.
His work on this can be found here.
For this .autoComplete of Jquery can be used.
HTML is like
<table><tr><td><input type="textbox" id="textBoxid" /> <div id="targetDiv" style="z-index:10"></div>
Jquery code will be like
$(function () {
$("#textBoxid").autocomplete({
appendTo: "#targetDiv",
position: { at: "bottom bottom" },
source: function (request, response) {
$.ajax({
url: '#Url.Action("ActionMethod", "Controller")',
type: "POST",
dataType: "json",
data: { searchString: request.term },
success: function (data) {
response($.map(data, function (item) {
return { label: item.ColumnValue, Id:item.ColumnId }
}))
}
})
},
select: function (event, ui) {
if (ui.item) {
// for saving the selected item id or any other function you wanna perform on selection
$('#hiddenfield').val($.trim(ui.item.Id));
}
}
});
Action Method will be like
[HttpPost]
public JsonResult MaterialDesc(string searchString)
{
// On searchString basis you can have your code to fetch data from database.
}
hope it can help you
:)
Ok, so, I have this lovely view here:
<p>
#using (Html.BeginForm("ConfirmSendItems", "Inventory"))
{
<table>
<tr>
<th>Item Name</th>
<th>Other Actions</th>
</tr>
#for (int i = 0; i < Model.ListItems.Count; i++)
{
<tr>
<td>#Ajax.ActionLink(#Model.ListItems[i].m_OtrObj.m_ObjName.ToString(), "GetObjProperties", new {id = #Model.ListItems[i].m_ItemID}, new AjaxOptions{ HttpMethod = "GET", UpdateTargetId = "result", InsertionMode = InsertionMode.Replace, OnSuccess = "openPopup"})</td>
</tr>
}
</table>
}
</p>
And these lovely scripts here :
<script src="/Scripts/jquery-1.7.1.min.js"
type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.20.js")" type="text/javascript"></script>
<script type="text/javascript">
function openPopup() {
alert("We have a new Pope-Up!");
$("#result").dialog("open");
}
</script>
Which shows the wanted message once I click on the link
I want to open a popUp window that will display the "/GetObjProperties/ method right here:
public PartialViewResult GetObjProperties(int? id)
{
ObjInfo objToDisplay = m_ObjManager.GetObjByID(id);
return PartialView(objToDisplay );
}
* EDIT *
Here's a resume of my question:
I want to make a link on the item's name that will open a pop-up window using a partial view.
* EDIT 2 *
As of right now, when I click, nothing is done. But if I right-click on the link and click on "Open in a new window", I get the exact good behavior. The problem remains that a pop-up does not open.
If you need a popup youll need to do it like this -->
<a href="#" onclick="Popup=window.open('testpage1.htm','Popup','toolbar=no,
location=no,status=no,menubar=no,scrollbars=yes,resizable=no,
width=420,height=400,left=430,top=23'); return false;">
Test Window</a>
A basic html example ;)
I hope this is answering your question I find it a little hard to understand what you want to achieve.
Check this
$(".objDialog").click(function() {
alert("Card Name has been clicked!");
window.open('/Inventory/GetCardProperties/', 'ObjProperties',
'heigth=' + (window.screen.height - 100) + ', width=200, left=' +
(window.screen.width - 250) + ',top=10,status=no,toolbar=no,resizable=yes,
scrollbars=yes,location=no,menubar=no');
});