I'm having trouble understanding how to retrieve and edit the DevId values from my CustomerDevice table in my database to the CheckBoxList based on the CustId value.
My Index Action Method for the CustomerDeviceController displays a list of Customers from my Customers table. I have an ActionLink labeled "Edit" that passes the CustId value to the CustomerDeviceController [HttpGet] Edit(int? id) Action Method which currently displays all CheckBoxListItem values from the Devices table. However, the CheckBoxList does not display the checked DevId values from the CustomerDevice table in the database to the CheckBoxList that pertain to the CustId, instead it displays a check for each of the CheckBoxList values.
The part that I'm having trouble understanding and figuring out, is how can I display the selected DevId values from the CustomerDevice table in my database to the CheckBoxList based on the CustId and then Edit/Update the modified CheckBoxListItems on the [HttpPost] Edit Action Method back to my CustomerDevice table in my database if need be.
Please see the following code below that I have so far.
Models
public class CheckBoxListItem
{
public int ID { get; set; }
public string Display { get; set; }
public bool IsChecked { get; set; }
}
public class Customer
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public string CustFirstName { get; set; }
....
}
public class Device
{
public int DevId { get; set; }
public string DevType { get; set; }
}
public class CustomerDevice
{
public int CustId { get; set; }
public int DevId { get; set; }
public Customer Customer { get; set; }
public Device Device { get; set; }
}
ViewModels
public class CustomerDeviceFormViewModel
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public List<CheckBoxListItem> Devices { get; set; }
}
CustomerDeviceController
public ActionResult Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var customervm = new CustomerDeviceFormViewModel();
Customer customer = db.Customers.SingleOrDefault(c => c.CustId == id);
if (customer == null)
{
return NotFound();
}
customervm.CustId = customer.CustId;
customervm.CustDisplayName = customer.CustDisplayName;
// Retrieves list of Devices for CheckBoxList
var deviceList = db.Devices.ToList();
var checkBoxListItems = new List<CheckBoxListItem>();
foreach (var device in deviceList)
{
checkBoxListItems.Add(new CheckBoxListItem()
{
ID = device.DevId,
Display = device.DevType,
IsChecked = deviceList.Where(x => x.DevId == device.DevId).Any()
});
}
customervm.Devices = checkBoxListItems;
return View(customervm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomerDeviceFormViewModel vmEdit)
{
if (ModelState.IsValid)
{
Customer customer = db.Customers.SingleOrDefault(c => c.CustId == vmEdit.CustId);
if (customer == null)
{
return NotFound();
}
foreach (var deviceId in vmEdit.Devices.Where(x => x.IsChecked).Select(x => x.ID))
{
var customerDevices = new CustomerDevice
{
CustId = vmEdit.CustId,
DevId = deviceId
};
db.Entry(customerDevices).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vmEdit);
}
Edit.chtml
<div class="form-group">
Please select the Devices to assign to <b>#Html.DisplayFor(c => c.CustDisplayName)</b>
</div>
<div class="form-group">
#Html.EditorFor(x => x.Devices)
</div>
#Html.HiddenFor(c => c.CustId)
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
Shared/EditorTemplate/CheckBoxListItem.chtml
<div class="checkbox">
<label>
#Html.HiddenFor(x => x.ID)
#Html.CheckBoxFor(x => x.IsChecked)
#Html.LabelFor(x => x.IsChecked, Model.Display)
</label>
<br />
Your code for setting the IsChecked value will always return true (your loop is basically say if the collection contains me (which of course it does) then set it to true).
You need to get the selected values for each Customer by reading the values from your CustomerDevice table
Customer customer = db.Customers.SingleOrDefault(c => c.CustId == id);
if (customer == null)
{
return NotFound();
}
// Get all devices
var deviceList = db.Devices.ToList();
// Get the selected device ID's for the customer
IEnumerable<int> selectedDevices = db.CustomerDevices
.Where(x => x.CustId == id).Select(x => x.DevId);
// Build view model
var model = new CustomerDeviceFormViewModel()
{
CustId = customer.CustId,
CustDisplayName = customer.CustDisplayName,
Devices = deviceList.Select(x => new CheckBoxListItem()
{
ID = x.DevId,
Display = x.DevType,
IsChecked = selectedDevices.Contains(x.DevId)
}).ToList()
};
return View(model);
Here's a snippet of Razor code that I've used:
foreach (SelectListItem p in Model.PositionList)
{
#Html.Raw(p.Text + "<input type=checkbox name=\"PositionIDs\" id=\"PositionIDs\" value=" + #p.Value + (Model.Positions != null && Model.Positions.Any(pos => pos.ScoreCardId == Convert.ToInt32(p.Value)) ? " checked />" : " />"));
}
You might want to have a look at the MvcCheckBoxList NuGet package:
https://www.nuget.org/packages/MvcCheckBoxList/
This makes doing some powerful stuff with a CheckBoxList much easier in MVC - and may be a better approach to fixing your CheckBox issues.
Related
I'm working with ASP.Net MVC with SQL server management studio.
Now how would I get a record by a given name and/or id?
Currently, I only find a record using the id which just works fine, but when searching a record by name, it won't find the correct record.
My current code looks something like this:
//Student.cs
public partial class Student
{
public int No { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Nullable<decimal> mobileno { get; set; }
public string Image { get; set; }
}
//Index.cshtml
#using (Html.BeginForm("search", "CrudManually", FormMethod.Post))
{
#Html.TextBox("id")<br/>
#Html.TextBox("searchString")<br/>
<input type="submit" value="Search"/>
}
//CrudManuallyController.cs
public class CrudManuallyController : Controller
{
public ActionResult Index()
{
return View(db.manages.ToList());
//return View();
}
[HttpPost]
public ActionResult search(int id,string searchString,Student students)
{
var query = db.students.Where(d => d.No == id).AsQueryable();
if (!string.IsNullOrEmpty(searchString))
{
query = query.Where(d => d.Name.Contains(searchs)); // generate an error local variable 'searchs' before it is declared.
}
var searchs = query.ToList();
return View("index",searchs);
}
}
Now how would I query for an id and a name at the same time?
update your controller
public class CrudManuallyController : Controller
{
public ActionResult Index()
{
return View(db.manages.ToList());
//return View();
}
[HttpPost]
public ActionResult search(int? id, string searchString,Student students)
{
//Lambda Linq to entity does not support Int32
//var search = (from d in db.students where d.No == Convert.ToInt32(id) && d.Name == id select d).ToList();
//var search = db.students.Where(d => d.No == Convert.ToInt32(id) && d.Name == id).ToList();
query = db.students.AsQueryable();
if (id.HasValue)
{
var studentId = id.Value;
query = query.Where(d => d.No == studentId);
}
if (!string.IsNullOrEmpty(searchString))
query = query.Where(d => d.Name.Contains(searchString));
var search = query.ToList();
return View("index",search);
}
}
update your .cshtml
#using (Html.BeginForm("search", "CrudManually", FormMethod.Post))
{
#Html.TextBox("id")
#Html.TextBox("searchString")
<br/>
<input type="submit" value="Search"/>
}
You can get 2 way
list.Where(i => i.Property == value).FirstOrDefault(); // C# 3.0+
list.Find(i => i.Property == value); // C# 3.0+
if you find any item, you can get that. If you dont find an item, you get null.
Tell me if you resolve :)
Need to create the edit View with selected Checkboxes from createView
public class CustomerTypeViewModel
{
[Required]
public int? Id { get; set; }
public string Description { get; set; }
[Display(Name = "Please select the Type")]
public bool Selected { get; set; }
}
CustomerView when i should load a list of CustomerTypeViewModel
public List<CustomerTypeViewModel> SelectedCustomerTypes { get; set; }
private List<CustomerTypeViewModel> selectionList = new List<CustomerTypeViewModel>();
public CustomerViewModel()
{
SelectedCustomerTypes = new List<CustomerTypeViewModel>();
}
public void SetCustomerTypeViewModel(IEnumerable<CustomerTypeViewModel> selected, IEnumerable<CustomerTypeViewModel> all)
{
SelectedCustomerTypes.Clear();
foreach (var item in all)
{
SelectedCustomerTypes.Add(item);
}
foreach (var item in selected)
{
SelectedCustomerTypes.FirstOrDefault(x => x.Description == item.Description).Selected = true;
}
}
public List<CustomerTypeViewModel> GetTipi()
{
return selectionList;
}
In controller i should call a method that get customertypes from manager
public CustomerTypeViewModel GetCustomerType(int? customerId)
{
var query = "SELECT * FROM CustomerType where Id = #Id";
return context.GetObject<CustomerTypeViewModel>(query, new { Id = customerId });
}
Now in the Edit at the Controller
[AuthorizeRoles(RoleNames.CanEditCustomer)]
public ActionResult Edit(int? id, int? customerId)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var customer = customerManager.Get(customerId);
var vm = new CustomerViewModel();
vm.SetCustomerTypeViewModel(new List<CustomerTypeViewModel>(), customerTypeManager.GetAll());
if (customer == null)
{
return HttpNotFound();
}
return View(customer);
}
I was told to create a method in manager GetCustomerType(customerId)
<-- this is the id from db table where checkboxes are saved and this method load a list of CustomerTypeViewModel
Now Edit View
<div class="form-group">
#{
for (int i = 0; i < Model.SelectedCustomerTypes.Count(); i++)
{
<div class="col-md-10">
#Html.Label(Model.SelectedCustomerTypes[i].Description, new { #class = "control-label col-md-2" })
#Html.CheckBoxFor(model => model.SelectedCustomerTypes[i].Selected, new { #checked = "checked" })
#Html.HiddenFor(model => model.SelectedCustomerTypes[i].Id, new { data_val = false })
#Html.HiddenFor(model => model.SelectedCustomerTypes[i].Description, new { data_val = false })
</div>
}
}
</div>
You need to fix the GetCustomerType method in your controller. Try this:
public IActionResult GetCostumerType(int? id)
{
if (id == null)
{
return NotFound();
}
var test = from custom in _yourContext.CustomerType
.Where(p => p.CustomerType.Id == customerId)
select custom;
//change _yourContext with your context variable
if (test == null)
{
return NotFound();
}
return View(test);
}
This way you are getting the custom types associated with the id passed in the method.
I have a simple select with an option selected from the model that is loaded.
To start here is my simple model
public class invoice
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public invoice_state invoice_state { get; set; }
}
public class invoice_state
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string alias { get; set; }
public List<invoice> invoices { get; set; }
[Display(Name = "title")]
public string title { get; set; }
}
Here is what I have that works in one view.
in controller:
public IActionResult Create()
{
string state = "start_finish";
ViewBag.State = state;
var states = _context.invoice_state.Select(c => new {
id = c.ID,
title = c.title
}).ToList();
ViewBag.States = new SelectList(states, "id", "title", _context.invoice_state.Where(e => e.alias == state).FirstOrDefault().ID);
return View();
}
in the view
#Html.DropDownList("invoice_state", (SelectList)ViewBag.States, "--Select One--")
That works fine, the option is selected... but on my edit view which is set up mostly the same is not working.
in controller:
public async Task<IActionResult> Edit(int? id)
{
var invoice = await _context.invoice
.Include(_item => _item.invoice_state).SingleOrDefaultAsync(m => m.ID == id);
if (invoice == null)
{
return NotFound();
}
string state = "start_finish"; // as a default
var states = _context.invoice_state.Select(c => new { id = c.ID, title = c.title }).ToList();
if (null != invoice.invoice_state)
{
ViewBag.State = invoice.invoice_state.alias;
}
else
{
ViewBag.State = state;
}
ViewBag.States = new SelectList(states, "id", "title", _context.invoice_state.Where(e => e.alias == state).FirstOrDefault());
return View(invoice);
}
and in the edit view
#Html.DropDownList("invoice_state", (SelectList)ViewBag.States, "--Select One--")
I have read all over the place and can't find a simple answer that isn't wire up more files, and even those haven't helped get me to the need. I have tried to force it too and it is not working, but figured it was worth placing here too.
ViewBag.States = _context
.invoice_state
.Select(c => new SelectListItem {
Value = c.ID.ToString(),
Text = c.title
})
.Select(l => new SelectListItem {
Selected = (l.Value == invoice.invoice_state.ID.ToString()),
Text = l.Text,
Value = l.Value
});
but only get 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem>' to 'Microsoft.AspNetCore.Mvc.Rendering.SelectList' or the list version of the error if i add .ToList() on the select like before.
Some people have suggested to set the selected value, and as i read it it would be like,
if (null != invoice.invoice_state)
{
ViewBag.invoice_stateID = invoice.invoice_state.ID;
}
else
{
ViewBag.invoice_stateID = _context.invoice_state.Where(e => e.alias == "start_finish").FirstOrDefault().ID;
}
if i use
<select asp-for="invoice_state" asp-items="#ViewBag.States" >
<option>Please select one</option>
</select>
It doesn't work either, see the list but nothing selected. Last note, if I select it and submit it, it does set the value in the database, just when I get back to the edit it again fails to again select anything.
Also to be clear there is the data
which came from
<dt>
#Html.DisplayNameFor(model => model.invoice_state)
</dt>
<dd>
#Html.DisplayFor(model => model.invoice_state)
</dd>
#Stephen Muecke is right, the ticket is the ViewModel. Not a fan fully here but I'll simmer. The solution is not just getting it to show, you need to save is too. Here is the whole of it.
ViewModel
namespace project_name.Models.InvoiceViewModel
{
public class EditInvoiceViewModel
{
public int invoice_stateID { get; set; }
public invoice invoice { get; set; }
public List<SelectListItem> States { set; get; }
}
}
edit in action on controller
public async Task<IActionResult> Edit(int? id)
{
var invoice = await _context.invoice
.Include(_item => _item.invoice_state).SingleOrDefaultAsync(m => m.ID == id);
string state = "start_finish"; // as a default
var states = _context.invoice_state.Select(c => new { id = c.ID, title = c.title }).ToList();
if (null != invoice.invoice_state)
{
ViewBag.State = invoice.invoice_state.alias;
}
else
{
ViewBag.State = state;
}
var vm = new EditInvoiceViewModel();
vm.invoice = invoice;
vm.States = _context
.invoice_state
.Select(c => new SelectListItem
{
Value = c.ID.ToString(),
Text = c.title
})
.ToList();
if (null != invoice.invoice_state)
{
vm.invoice_stateID = invoice.invoice_state.ID;
} else {
vm.invoice_stateID = _context.invoice_state.Where(e => e.alias == "start_finish").FirstOrDefault().ID;
}
return View(vm);
}
to save in action on controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(EditInvoiceViewModel model)
{
if (ModelState.IsValid)
{
try
{
model.invoice.creator = await GetCurrentUserAsync();
model.invoice.invoice_state = await _context.invoice_state.SingleOrDefaultAsync(m => m.ID == model.invoice_stateID);
_context.Update(model.invoice);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!invoiceExists(model.invoice.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("Index");
}
return View(model);
}
And in the view
<div class="form-group">
<label asp-for="#Model.invoice_stateID" class="col-md-2 control-label"></label>
<select asp-for="#Model.invoice_stateID" asp-items="#Model.States" >
<option>Please select one</option>
</select>
</div>
The thing I guess I was having a hard time with is all supporting questions that are like this, and all the blogs focus on the display, but i still need to save it, and that was not clear. I had to skip the [bind()] but I'll get back to that.
I'm using ASP.NET Core MVC, EntityFramework Core and C#.
I'm having trouble updating the CheckBoxList values to the CustomerDevice table in my Database on the [HttpPost] Edit Action Method CustomerDeviceController. The CustomerDevice table is a JOIN table that has a Many to Many between the Customer and Device tables.
My Index Action Method for the CustomerDeviceController displays a list of Customers from my Customers table. I have an ActionLink labeled "Edit" that passes the CustId value to the CustomerDeviceController [HttpGet] Edit(int? id) Action Method which then displays all selected DevId values assigned to the CustId to the CheckBoxList, this part works fine.
When I try to update the CheckBoxList values now it adds the DevId values that I choose to remove and the DevId values that I want to keep it removes.
So for Example: If I initially added DevId values (1, 3, 4 and 7) for CustId 1006 and then decide to Edit to remove just DevId value 1 it actually removes DevId values (3, 4 and 7) and leaves DevId value 1.
Models
public class CheckBoxListItem
{
public int ID { get; set; }
public string Display { get; set; }
public bool IsChecked { get; set; }
}
public class Customer
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public string CustFirstName { get; set; }
public string CustLastName { get; set; }
public List<CustomerDevice> CustomerDevices { get; set; }
}
public class CustomerDevice
{
public int CustId { get; set; }
public int DevId { get; set; }
public Customer Customer { get; set; }
public Device Device { get; set; }
}
public class Device
{
public int DevId { get; set; }
public string DevType { get; set; }
public List<CustomerDevice> CustomerDevices { get; set; }
}
public class WebFormContext : DbContext
{
public WebFormContext(DbContextOptions<WebFormContext> options)
: base(options)
{ }
public DbSet<Customer> Customers { get; set; }
public DbSet<Device> Devices { get; set; }
public DbSet<CustomerDevice> CustomerDevices { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>()
.HasKey(c => c.CustId);
modelBuilder.Entity<Customer>()
.Property(c => c.CustDisplayName)
.HasColumnType("varchar(100)")
.HasMaxLength(100)
.IsRequired();
modelBuilder.Entity<Customer>()
.Property(c => c.CustFirstName)
.HasColumnType("varchar(50)")
.HasMaxLength(50);
modelBuilder.Entity<Customer>()
.Property(c => c.CustLastName)
.HasColumnType("varchar(50)")
.HasMaxLength(50);
modelBuilder.Entity<Device>()
.HasKey(d => d.DevId);
modelBuilder.Entity<Device>()
.Property(d => d.DevType)
.HasColumnType("varchar(50)")
.HasMaxLength(50)
.IsRequired();
modelBuilder.Entity<CustomerDevice>()
.HasKey(c => new { c.CustId, c.DevId });
modelBuilder.Entity<CustomerDevice>()
.HasOne(cd => cd.Customer)
.WithMany(c => c.CustomerDevices)
.HasForeignKey(cd => cd.CustId);
modelBuilder.Entity<CustomerDevice>()
.HasOne(cd => cd.Device)
.WithMany(d => d.CustomerDevices)
.HasForeignKey(cd => cd.DevId);
}
}
ViewModel
public class CustomerDeviceFormViewModel
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public List<CheckBoxListItem> Devices { get; set; }
}
Controller
public class CustomerDeviceController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
return View(db.Customers.ToList());
}
public ActionResult Edit(int? id)
{
Customer customer = db.Customers.SingleOrDefault(c => c.CustId == id);
if (customer == null)
{
return NotFound();
}
// Get all devices
var deviceList = db.Devices.ToList();
// Get the selected device ID's for the customer
IEnumerable<int> selectedDevices = db.CustomerDevices
.Where(x => x.CustId == id).Select(x => x.DevId);
// Build view model
var model = new CustomerDeviceFormViewModel()
{
CustId = customer.CustId,
CustDisplayName = customer.CustDisplayName,
Devices = deviceList.Select(x => new CheckBoxListItem()
{
ID = x.DevId,
Display = x.DevType,
IsChecked = selectedDevices.Contains(x.DevId)
}).ToList()
};
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomerDeviceFormViewModel vmEdit)
{
if (ModelState.IsValid)
{
Customer customer = db.Customers
.Include(c => c.CustomerDevices)
.SingleOrDefault(c => c.CustId == vmEdit.CustId);
if (customer == null)
{
return NotFound();
}
IEnumerable<int> selectedDevices = vmEdit.Devices.Where(x => x.IsChecked).Select(x => x.ID);
// Add the new selected devices
foreach (int deviceId in selectedDevices)
{
var customerDevice = customer.CustomerDevices.FirstOrDefault(cd => cd.DevId == deviceId);
if (customerDevice != null)
{
customer.CustomerDevices.Remove(customerDevice);
}
else
{
CustomerDevice custDevice = new CustomerDevice
{
CustId = customer.CustId,
DevId = deviceId
};
customer.CustomerDevices.Add(custDevice);
}
}
// Update the customer
db.Customers.Update(customer); //or just db.Update(customer); same thing
// Save and redirect
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vmEdit);
}
}
Shared/EditorTemplates/CheckBoxListItem.chtml
<div class="checkbox">
<label>
#Html.HiddenFor(x => x.ID)
#Html.CheckBoxFor(x => x.IsChecked)
#Html.LabelFor(x => x.IsChecked, Model.Display)
</label>
<br />
Edit View
<div class="form-group">
Please select the Devices to assign to <b>#Html.DisplayFor(c => c.CustDisplayName)</b>
</div>
<div class="form-group">
#Html.EditorFor(x => x.Devices)
</div>
#Html.HiddenFor(c => c.CustId)
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
I have the following form:
#model Teesa.Models.SearchModel
#using (Html.BeginForm("Index", "Search", FormMethod.Get, new { id = "SearchForm" }))
{
<div class="top-menu-search-buttons-div">
#if (!MvcHtmlString.IsNullOrEmpty(Html.ValidationMessageFor(m => m.SearchText)))
{
<style type="text/css">
.top-menu-search-text
{
border: solid 1px red;
}
</style>
}
#Html.TextBoxFor(q => q.SearchText, new { #class = "top-menu-search-text", id = "SearchText", name = "SearchText" })
#Html.HiddenFor(q=>q.Page)
<input type="submit" value="search" class="top-menu-search-submit-button" />
</div>
<div id="top-menu-search-info" class="top-menu-search-info-div">
Please Select one :
<hr style="background-color: #ccc; height: 1px;" />
<div class="top-menu-search-info-checkbox-div">
#Html.CheckBoxFor(q => q.SearchInBooks, new { id = "SearchInBooks", name = "SearchInBooks" })
<label for="SearchInBooks">Books</label>
</div>
<div class="top-menu-search-info-checkbox-div">
#Html.CheckBoxFor(q => q.SearchInAuthors, new { id = "SearchInAuthors" })
<label for="SearchInAuthors">Authors</label>
</div>
<div class="top-menu-search-info-checkbox-div">
#Html.CheckBoxFor(q => q.SearchInTags, new { id = "SearchInTags" })
<label for="SearchInTags">Tags</label>
</div>
}
and the following Controller and Models :
namespace Teesa.Models
{
public class SearchModel
{
[Required(ErrorMessage = "*")]
public string SearchText { get; set; }
public bool SearchInTags { get; set; }
public bool SearchInAuthors { get; set; }
public bool SearchInBooks { get; set; }
public int Page { get; set; }
public List<SearchBookModel> Result { get; set; }
public List<SimilarBookModel> LatestBooks { get; set; }
}
public class SearchBookModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Summary { get; set; }
public List<Tags> Tags { get; set; }
public string StatusName { get; set; }
public string SubjectName { get; set; }
public string ThumbnailImagePath { get; set; }
public string BookRate { get; set; }
public string RegistrationDate { get; set; }
public int NumberOfVisit { get; set; }
}
}
[HttpGet]
public ActionResult Index(SearchModel model)
{
FillSearchModel(model);
if (ModelState.IsValid)
{
string page = model.Page;
DatabaseInteract databaseInteract = new DatabaseInteract();
model.Result = new List<SearchBookModel>();
List<Book> allBooks = databaseInteract.GetAllBooks();
List<Book> result = new List<Book>();
#region
if (model.SearchInTags)
{
var temp = (from item in allBooks
from tagItem in item.Tags
where tagItem.Name.Contains(model.SearchText)
select item).ToList();
result.AddRange(temp);
}
if (model.SearchInBooks)
{
var temp = (from item in allBooks
where item.عنوان.Contains(model.SearchText)
select item).ToList();
result.AddRange(temp);
}
if (model.SearchInAuthors)
{
var temp = (from item in allBooks
where item.Author.Contains(model.SearchText)
select item).ToList();
result.AddRange(temp);
}
#endregion
#region Paging
string itemsPerPage = databaseInteract.GetItemsPerPage();
int ItemInPage = int.Parse(itemsPerPage);
var pagingParams = Helpers.SetPagerParameters(page, ItemInPage, result);
ViewBag.AllPagesCount = pagingParams.AllPagesCount;
ViewBag.CurrentPageNumber = pagingParams.CurrentPageNumber;
ViewBag.CountOfAllItems = pagingParams.CountOfAllItems.ToMoneyFormat().ToPersianNumber();
result = pagingParams.ListData as List<Book> ?? result;
#endregion
foreach (var item in result)
{
var bookRate = (item.BookRate == null || item.BookRate.Count == 0)
? 0.0
: item.BookRate.Average(q => q.Rate);
model.Result.Add(new SearchBookModel
{
Author = item.Author,
Id = item.Id,
.
.
.
});
}
}
else
{
model.Result = new List<SearchBookModel>();
}
return View(model);
}
When I submit the form I see the following query strings(Notice the duplicate names) :
http://localhost:2817/Search?SearchText=book&Page=2&SearchInBooks=true&SearchInBooks=false&SearchInAuthors=true&SearchInAuthors=false&SearchInTags=true&SearchInTags=false
But it has to be something like this :
http://localhost:2817/Search?SearchText=book&Page=2&SearchInBooks=true&SearchInAuthors=true&SearchInTags=true
How can I fix it ?
Thanks
Html.Checkbox (and the related For... methods) generate a hidden input for false, and the checkbox for true. This is to ensure that model binding works consistently when binding.
If you must get rid of "false" items resulting from the hidden inputs, you'll need to construct the checkbox inputs yourself (using HTML and not the helper).
<input type="checkbox" id="SearchInBooks" name="SearchInBooks">
Why dont your create a Post Method with a matching name to the Get method. This will ensure that the code is much easier to debug. As you will not have a huge function to go through trying to find problems like this.
I cannot find a where your getting the duplicate url query strings from though.
This will also allow you to bind your results back to the model.
If you want the model binding to happen successfully then you have to go with this way because that is the nature of the Html.CheckBox/Html.CheckBoxFor methods they will render a hidden field as well.
I would suggest rather go with POST to make your life easy. If you still want to use GET then you have to use checkbox elements directly but you have to take care of the model binding issues. Not all the browsers returns "true" when the checkbox is checked for ex. firefox passes "on" so the default model binder throws an error.
Other alternate options is you can go for custom model binder or you can submit the form using jquery by listening to the submit event.