How can I easily append data from checkboxes in MVC? - javascript

I want to append HTML/data to div when the checkboxes is checked. I also want to know the best practices to how append data/html easily from the checkboxes.
However, please see the code below:
Ajax
$('.myCheck').on('ifChecked', function (event) {
$.ajax({
url: '/Home/getCategoryItems',
type: "GET",
cache: false,
data: {
name: $(this).attr("name")
},
success: function (data) {
setTimeout(function () {
}, 3000);
}
});
});
View:
#foreach (var item in Model.Cars)
{
<span class="label">
#item.CategoryName <span class="badge">#item.CategoryCount</span>
</span>
#Html.CheckBox(item.CategoryName, new { #class = "myCheck", })
#Html.Hidden("name", item.CategoryName, new { id = item.CategoryId })
}
Controller:
[HttpGet]
public JsonResult getCategoryItems(string name)
{
var select = (from r in _db.Cars
where r.Category.Name == name
select new
{
r.Title,
r.Price,
r.FileName,
r.Category.Name,
r.City,
r.TagName,
r.Id,
}).ToList();
return new JsonResult { Data = select, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
This is what I want to append:
#foreach (var item in Model)
{
<div class="container" id="sek1">
<div class="row">
<div class="col-md-12 no-padding-lr sear-result-column">
<div class="latest-job article-row1">
<div class="col-md-2 no-padding-lr resp-grid1 box-sadow">
<img src="https://wp-themes.com/wp-content/themes/jobile/images/no-image.jpg" width="100" height="86">
</div>
<div class="col-md-10 no-padding-lr">
<div class="col-md-8 col-sm-8 col-xs-8 no-padding-lr job-status resp-grid1 job-status-3">
<h3>#item.Title</h3>
</div>
<div class="col-md-4 col-sm-4 col-xs-4 job-status resp-grid1 job-status-3">
<a class="btn btn-primary" id="LesMerBtn">#item.Price</a>
</div>
<div class="col-md-12 no-padding-lr">
<div class="job-btn-group late-job-btn clearfix">
<span class="glyphicon glyphicon-map-marker"></span>#item.City
<span class="glyphicon glyphicon-list-alt"></span>Kategori: #item.CategoryName
</div>
</div>
<div class="col-md-12 no-padding-lr">
<p class="result-btm-text"></p><p>Test....</p>
<span class="glyphicon glyphicon-eye-open" id="eye-open"></span>Read more<p></p>
</div>
</div>
</div>
</div>
</div>
</div>
}

You will get the json response in your success event of your ajax call. The response is of an array and you need to iterate through the array and get each item in the array, read the property values and use that to build your html markup you want to append.
success: function (data) {
var myHtml="";
$.each(data,function(a,b){
myHtml+="<div><p>"+b.Title+"</p>";
myHtml+="<p>"+b.City+"</p>";
myHtml+="<p>"+b.Price+"</p></div>";
});
$("#YourDivId").append(myHtml);
}
Assuming YourDivId is the Id of the Div where you want to show the data coming from your ajax call and this div exists in your page.
This works if you are making simple html markup. But if you have some complicated markup you want to appen/show. i recommend returning a partial view from your ajax call.
So in your action method, instead of returning the json data, pass that data to your partial view and let the action method returns the razor generated html markup with the data.
Assuming you have a view model like this to represent a Car
public class CarVm
{
public string Title { set;get;}
public decimal Amount { set;get;}
public string City { set;get;}
}
In your action method, create a list of CarVm from the data from your db table and pass that to the partial view.
[HttpGet]
public JsonResult getCategoryItems(string name)
{
var carVmList= (from r in _db.Cars
where r.Category.Name == name
select new CarVm { Title =r.Title,
City =r.City,
Price=r.Price
}
).ToList();
return PartiaView("CarsPerCategory",carVmList);
}
Assuming you have a partial view called CarsPerCategory.cshtml which is strongly typed to a collection of CarVm type. The partial view should exist in either ~/Views/Shared/ or ~/Views/YourCurrentControllerName/
#model List<CarVm>
#foreach (var item in Model)
{
<p>#item.Title</p>
<!-- Add the remaining markup you want (same as the code in your question) -->
}
And in your success event you simply append the response coming back to your container div.
success: function (data) {
$("#YourDivId").append(data);
}
you may use append() method or html() method depending on you want to replace the existing value or just append it.

Related

ASP.NET Core - change form action to list options in view

I have controller for changing website language, saving cookie and returning url.
`
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
namespace Website.Controllers;
public class CultureController : Controller
{
[HttpPost]
public IActionResult SetCulture(string culture, string returnUrl)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddDays(365) }
);
return LocalRedirect(returnUrl);
}
}
`
And in View I need create html list for better user experience but I don't understand how to change from 'form' to 'list' or how to submit changes and return url
`
#using Microsoft.AspNetCore.Localization
#using Microsoft.Extensions.Options
#inject IOptions<RequestLocalizationOptions> LocalizationOptions
#{
var requestCulture = Context.Features.Get<IRequestCultureFeature>();
var cultureItems = LocalizationOptions.Value.SupportedUICultures
.Select(c => new SelectListItem { Value = c.Name, Text = c.EnglishName })
.ToList();
var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}{Context.Request.QueryString}";
}
<!-- FROM FORM -->
<div class="language">
<form asp-controller="Culture" asp-action="SetCulture" asp-route-returnUrl="#returnUrl" class="form-horizontal nav-link text-dark">
<select name="culture"
onchange="this.form.submit();"
asp-for="#requestCulture.RequestCulture.UICulture.Name"
asp-items="cultureItems">
</select>
</form>
</div>
<!-- TO LIST -->
<div class="language-toggle">
<i class="fas fa-language"></i>
<ul class="language-menu">
#foreach (var item in LocalizationOptions.Value.SupportedUICultures)
{
<li>#item.Name.ToUpper()</li>
}
</ul>
</div>
`
I tried with anchor tag helper but without success
output
Output
I can get current url in view and append ?culture=en and that changes language and stays on current page but does not save cookie so every time user goes to different page website is in native language not in user selected language.
You can achieve that with something like this:
<head>
<script type="text/javascript">
function submitCulForm(val) {
document.getElementById("cultureVal").value = val;
var hh = document.getElementById("cultureForm");
hh.submit();
return false;
}
</script>
</head>
Then
<form asp-controller="Culture" id="cultureForm" asp-action="SetCulture" asp-route-returnUrl="#returnUrl" class="form-horizontal nav-link text-dark">
<input id="cultureVal" type="hidden" name="culture" value="-">
<div class="language-toggle">
<i class="fas fa-language"></i>
<ul class="language-menu">
#foreach (var item in LocalizationOptions.Value.SupportedUICultures)
{
<li>#item.Name.ToUpper()</li>
}
</ul>
</div>
</form>
If you try to pass the value with herf,you shouldn't add [HttpPost] Attribute on your controller.
I tried with the codes in your controller,it works well,I'll show what I've tried and hopes it could help
in View:
<div>
<a asp-action="SetCulture" asp-route-culture="zh-CN">zh-CN</a>
<a asp-action="SetCulture" asp-route-culture="en-US">en-US</a>
</div>
<script>
var cookie = document.cookie
console.log(cookie)
</script>
in Controller:
public IActionResult SetCulture(string culture)
{
if (culture != null)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddDays(365) });
return RedirectToAction("Create");
}
return BadRequest();
}
Configure in startup:
services.AddControllersWithViews()
.AddDataAnnotationsLocalization(
options =>
{
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResources));
});
...............
var supportedCultures = new[] { "en-US", "zh-CN" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
created an empty class called SharedResources
and the resourcefile:
The Result:
It just performed as the document,and if you tried with mulipule providers,you could try to change request culture providers order which has been mentioned in the document

Ajax search doesn't work the second time (ASP.NET MVC)

I have a problem changing items after searching.
I looked at similar threads but found no solution there :(
It looks like the first time the page loads well - the first time the entire Index.cshtml page is loaded which contains a collection of books in the selected category.
There is a search engine on the page - after searching for "manual" - ajax correctly replaces elements with those containing "manual" in the name.
Then when I enter something into the search engine a second time (for example "exercises") - the content of the page does not change any more.
I tried to debug and I see that new items are correctly downloaded from the database - the condition "if (Request.IsAjaxRequest ())" is true and the items are passed to partial view - there the "foreach" loop goes through them. Unfortunately, after _Partial, nothing happens.
I can't find a mistake - the strangest thing is that the first ajax call works fine - only the second (and subsequent) bad.
CatalogController.cs
public ActionResult Index(string categoryName = null, string searchQuery = null)
{
if (categoryName == null)
categoryName = (db.Categories.Find(1)).Name;
var category = db.Categories.Include("Books").Where(x => x.Name.ToLower() == categoryName).Single();
var books = category.Books.Where(x => (searchQuery == null || x.Title.ToLower().Contains(searchQuery.ToLower()) || x.SubTitle.ToLower().Contains(searchQuery.ToLower()) || x.Level.ToLower().Contains(searchQuery.ToLower())) && !x.Inaccessible);
if (Request.IsAjaxRequest())
return PartialView("_PartialBooksList", books);
else
return View(books);
}
Index.cshtml
<form class="o-search-form" id="search-form" method="get" data-ajax="true" data-ajax-target="#booksList">
<input class="o-search-input" id="search-filter" type="search" name="searchQuery" data-autocomplete-source="#Url.Action("SearchTips")" placeholder="Search" />
<input class="o-search-submit" type="submit" value="" />
</form>
<div class="row" id="booksList">
#Html.Partial("_PartialBooksList")
</div>
#section Scripts
{
<script src="~/Scripts/jquery-3.5.0.js"></script>
<script src="~/Scripts/jquery-ui-1.12.1.js"></script>
<script>
$(function () {
var setupAutoComplete = function () {
var $input = $(this);
var options =
{
source: $input.attr("data-autocomplete-source"),
select: function (event, ui) {
$input = $(this);
$input.val(ui.item.label);
var $form = $input.parents("form:first");
$form.submit();
}
};
$input.autocomplete(options);
};
var ajaxSubmit = function () {
var $form = $(this);
var settings = {
data: $(this).serialize(),
url: $(this).attr("action"),
type: $(this).attr("method")
};
$.ajax(settings).done(function (result) {
var $targetElement = $($form.data("ajax-target"));
var $newContent = $(result);
$($targetElement).replaceWith($newContent);
$newContent.effect("slide");
});
return false;
};
$("#search-filter").each(setupAutoComplete);
$("#search-form").submit(ajaxSubmit);
});
</script>
}
_PartialBooksList
#model IEnumerable<ImpressDev.Models.Book>
#using ImpressDev.Infrastructure
<div class="row">
#foreach (var book in Model)
{
<div class="col-12 col-xl-4">
<a class="o-shop-link" href="#Url.Action("Details", "Catalog", new { bookId = book.BookId })">
<div class="o-shop-item">
<img class="o-shop-img" src="#Url.BookPhotoSourcePath(book.PhotoSource)" />
<div class="o-shop-text">
<h2>#book.Title</h2>
<h6>#book.SubTitle - #book.Level - <b>#book.Price zł.</b></h6>
+ Add to cart
</div>
</div>
</a>
</div>
}
</div>
Please help
I am not sure if this is the case, but try to change this code:
$($targetElement).replaceWith($newContent);
To this:
$($targetElement).html($newContent);
I think the problem is the div element with id="booksList" is replaced after first search. So you don't have this element in the second search.
I looked through the code step by step and found a solution to my problem.
In the first search, replace id="booksList"
<div class="row" id="booksList">
#Html.Partial("_PartialBooksList")
</div>
partial view in which there was only without id = booksLists.
In the next search there was no ID in this place and there was nothing to replace.

Ajax redirecting when it is not supposed to [duplicate]

This question already has answers here:
jQuery ID selector works only for the first element
(7 answers)
Closed 6 years ago.
I've implemented a program something like a shopping cart where you would add products to the cart. I'm using ajax make the page dynamic so multiple products can be added to the cart without a page reload. For some reason, the first product in the list can be added correctly while the rest of products alway redirects to the controller url when it isn't supposed to.
View Code
<section class="grid grid--loading" id="portfoliolist">
<!-- Loader -->
<img class="grid__loader" src="~/Images/grid.svg" width="60" alt="Loader image" />
<!-- Grid sizer for a fluid Isotope (Masonry) layout -->
<div class="grid__sizer"></div>
<!-- Grid items -->
#foreach (var item in Model.ProductsList)
{
var pricetag = "pricegroup3";
if (item.Price <= 300)
{
pricetag = "pricegroup1";
}
else if (item.Price > 300 && item.Price <= 500)
{
pricetag = "pricegroup2";
}
<div class="grid__item #item.Type #pricetag">
<div class="slider">
#foreach (var image in Model.ProductImagesList.Where(m=>m.ProductID == item.Id))
{
<div class="slider__item"><img src="~/Images/Products/#image.Image" /></div>
}
</div>
<div class="meta">
<h3 class="meta__title">#item.Name</h3>
<span class="meta__brand">#item.Brand</span>
<span class="meta__price">R #item.Price</span>
</div>
<a class="action action--button action--buy" href="#Url.Action("AddToPlatform", "ProductPlatforms", new { ProdID = item.Id })" id="platformAdd" data-value="#item.Id"><i class="fa fa-shopping-cart"></i><span class="text-hidden">Add to Platform</span></a>
</div>
}
</section>
The last tag is what will be clicked on to add the product to the cart.
Script -Ajax
$("#platformAdd").click(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: $(this).attr("href"),
success: toastr["success"]("Product added to Platform")
});
});
Controller function
public void AddToPlatform(int ProdID)
{
var currUser = User.Identity.GetUserId();
DateTime now = DateTime.Now;
var exists = ProductExists(ProdID);
if (exists == false)
{
ProductPlatform prodPlatform = new ProductPlatform()
{
ProductID = ProdID,
UserID = currUser,
ViewedStatus = false,
DateAdded = now
};
db.ProductPlatforms.Add(prodPlatform);
db.SaveChanges();
}
}
The ajax script function would call the controller function which will add the product to the cart. Since there are no redirects I can't seem to figure out why the ajax call redirects to the tag "href".
Thanks for any help!
You need to use class instead of id because ids are always unique.
$(".lnkAddProduct").click(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: $(this).attr("href"),
success: function(){alert("ADDED");}
});
});

change an element's text with variable id

I am designing a social network that has timeline and there is like button. I use AJAX to apply the like button on the server side. the problem is that I want to change the number of like for each post immediately after they have liked successfully. Because my elements are generated by for-each, I want to change the number of like for the exact element, I really have a problem with it.I am using thymeleaf.
I am looking for an idea that how to do this.
here is my html code:
<div class="col-sm-4">
<div class="row" >
<div class="col-sm-12">
<img th:if="${tweet.isFavorited()}" src="../static/images/like.png" th:src="#{/images/like.png}" th:class="like-img" th:id="${tweet.getId()}" width="35" height="35"/>
<img th:if="${!tweet.isFavorited()}" src="../static/images/dislike.png" th:src="#{/images/dislike.png}" th:class="like-img" th:id="${tweet.getId()}" width="35" height="35"/>
</div>
</div>
<div class="row">
<div class="col-sm-12" >
<h6 th:if="${tweet.isRetweet()}" th:class="like-count" th:id="${tweet.getId()}" th:text="${tweet.getRetweetedStatus().getFavoriteCount()}"></h6>
<h6 th:if="${!tweet.isRetweet()}" th:class="like-count" th:id="${tweet.getId()}" th:text="${tweet.getFavoriteCount()}"></h6>
</div>
</div>
and it is my script code:
$(function () {
$(".like-img").click(function () {
event.preventDefault();
var $post = $(this);
var toSend = {
"tweetId": this.getAttribute("id")
}
$.ajax({
type : "POST",
contentType: "application/json; charset=utf-8",
url : "like",
data : JSON.stringify(toSend),
dataType : 'json'
}).done(function (data) {
if(data.status == "success") {
if ($($post).attr("src") == "/images/dislike.png") {
$($post).attr('src','/images/like.png');
}
else {
$($post).attr('src','/images/dislike.png');
}
return false;
}
});
});
})
Okay so to make this work you will need to assign unique ids to the like-count elements, something like so:
<h6 th:if="${tweet.isRetweet()}" th:class="like-count" th:id="${tweet.getId()}_like_count" th:text="${tweet.getRetweetedStatus().getFavoriteCount()}"></h6>
Then you can retrieve the current count, increment it, and set the text of the count element. Something like so:
var currentCount = parseInt($('#'+toSend.tweetId+'_like_count').innerHtml)
var newCount = currentCount++;
$('#'+toSend.tweetId+'_like_count').text(newCount);

asp.net mvc serialize() returns empty in controller's model

snippet of my cshtml:
#model Models.ClockingInformationViewModel
<form id="clocking-form">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Time in</label>
<div class="input-group date form_datetime">
#Html.TextBoxFor(m => m.Attendance.Time01In, new { #class = "form-control", #readonly = "readonly", size = "16" })
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Job code</label>
#Html.TextBoxFor(m => m.Attendance.Time01InJob, new { #class = "form-control" })
Controller:
[HttpPost]
public JsonResult ClockingInformation(ClockingInformationViewModel model)
{
return null;
}
ViewModel:
public class ClockingInformationViewModel
{
public Attendance Attendance { get; set; }
public List<Clock> ClockingLocations { get; set; }
}
In my javascript, I have this:
function saveClockingInformation() {
var data = $("#clocking-form").serialize();
$.post($("#clocking-info-url").val(), { model: data });
}
When I set a break point in my controller, ClockingInformationViewModel model property is null.
When I did serializeArray() instead of serialize(), ClockingInformationViewModel model isn't null, but the property Attendance is.
I'm sure it's some silly mistake that I've over looked.
Any insights?
Your var data = $("#clocking-form").serialize(); line of code is already serializing your form to an object, so the code needs to be
function saveClockingInformation() {
var data = $("#clocking-form").serialize();
$.post($("#clocking-info-url").val(), data);
}
Which sends the form data as
Attendance.Time01In=someValue&Attendance.Time01InJob=anotherValue
whereas your current implementation using { model: data } sends the form data as
model[Attendance.Time01In]=someValue&model[Attendance.Time01InJob]=anotherValue
which has no relationship to your model, hence binding fails.
Side note: Your use of $("#clocking-info-url").val() suggests you putting the url in to a hidden input. Instead, use
var url = '#Url.Action("yourAction", "yourController")',
$.post($(url, data);
or if you have generated the form using Html.BeginForm(), then use
var form = $("#clocking-form");
var url = form.attr('action');
$.post($(url, data);

Categories