I have an Index (List) View in MVC5, that is populated from a model (Table ICS_Supplies).
I have added a textbox to add search filter for the users, on field ItemDescription (varchar). This works perfectly fine as follows:
View
<form asp-controller="Movies" asp-action="Index">
<p>
Search Supplies: <input type="text" name="SearchString">
<input type="submit" value="Filter" />
</p>
</form>
Controller
public ActionResult Index(string searchString, string SType, int? page, string YourRadioButton)
{
// Add SearchBox Filter
var catalogs = supplies.Where(s => s.ItemDescription.Contains(searchString ?? string.Empty));
// Add paging to the search results
var pageNumber = page ?? 1;
return View(catalogs.ToPagedList(pageNumber, 10));
}
This works perfectly. If the searchString is null, it brings back ALL results. IF the searchSring has a value, it brings back any results where ItemDescription Cotain the searchString Value.
I am trying to add a radiobutton to the index view so that the user can also filter on the field InvType, which is a char(1) field. It can be F (for Forms) or S (for supplies). So, I set the value of YourRadioButton to F or S depending on which is selected. . . as follows (with new code)
Index
<form asp-controller="Movies" asp-action="Index">
<div>
Supplies: #Html.RadioButton("YourRadioButton", "S")
Forms: #Html.RadioButton("YourRadioButton", "F")
</div>
<p>
Search Supplies: <input type="text" name="SearchString">
<input type="submit" value="Filter" />
</p>
</form>
And I update the Controller with additional code, as follows:
public ActionResult Index(string searchString, string SType, int? page, string YourRadioButton)
{
var supplies = db.ICS_Supplies.OrderBy(g => g.ItemDescription).ToList();
//var supplies2 = supplies.Where(s => s.InvType.Equals(mychoice));
var supplies2 = supplies.Where(s => s.InvType.Contains(YourRadioButton ?? string.Empty));
// Add SearchBox Filter
var catalogs = supplies2.Where(s => s.ItemDescription.Contains(searchString ?? string.Empty));
// Add paging to the search results
var pageNumber = page ?? 1;
return View(supplies2.ToPagedList(pageNumber, 10));
}
Now, I receive The following error
System.NullReferenceException
And it is referring to the following line of code (which I added)
var supplies2 = supplies.Where(s => s.InvType.Contains(YourRadioButton ?? string.Empty));
My question(s) are . . . Why does that kick out a NullReferenceException, but the other line works perfectly fine if it is null? And how do I resolve the issue - or is there a better way to add this second filter to my code?
This line works fine, null or not. They are both identical in how they are written, other than the Value of YourRadioButton is used, instead of searchString, and I am using InvType field instead of ItemDescription.
var catalogs = supplies2.Where(s => s.ItemDescription.Contains(searchString ?? string.Empty));
Keep in mind that I am VERY new to both MVC5 and C#, and so explaining why would help me a great deal to progress.
There does not seem to be a lot of information out there, in regards to using radio buttons in MVC5 . . . a rather simple concept in old Asp.net forms.
It seems that some entries of suppliers doesn't have an InvType. That property is sometimes null, therefore you receive a NullReferenceException because you are calling Contains() method on a null value property.
The problem doesn't occur in your first example, because you were using Linq to Entities.
In the second example you are calling ToList() after the first query. After that, everything will continue to work in memory (Linq to Objects). Then you have to check for null in any where condition:
var supplies2 = supplies.Where(s => s.InvType != null && s.InvType.Contains(YourRadioButton ?? string.Empty));
I think it is better to remove ToList() from the first query. Add your where conditions to it and let the PagedList execute the query for you:
public ActionResult Index(string searchString, string SType, int? page, string YourRadioButton)
{
var supplies = db.ICS_Supplies.AsQueryable();
if (!String.IsNullOrWhiteSpace(YourRadioButton))
{
supplies = supplies.Where(s => s.InvType.Contains(YourRadioButton));
}
if (!String.IsNullOrWhiteSpace(searchString))
{
supplies = supplies.Where(s => s.ItemDescription.Contains(searchString));
}
supplies = supplies.OrderBy(g => g.ItemDescription)
// Add paging to the search results
var pageNumber = page ?? 1;
return View(supplies.ToPagedList(pageNumber, 10));
}
Related
I'm trying to pull a list of Ids and Usernames from an Audit table that is populated with Ids from a separate table, and usernames of people who voted on an Idea.
The flow should be:
See an Idea
Click the Vote button
Add the Idea Id, logged in User, and DateTime they clicked the Vote button to the IdeaBoardVote table.
Disable Vote button if after querying the IdeaBoardVote table, the IdeaId and Username match an IdeaBoard records Id and Username.
I'm trying to use foreach to loop through the IdeaBoardVote table to find matches, but I get the following error:
'System.Web.Mvc.SelectListItem' does not contain a definition for 'IdeaId'
Here is my Controller code to populate the list:
[HttpGet]
public ActionResult Index(int page = 1, string message = "")
{
ViewBag.Message = message;
if (!Request.IsAuthenticated)
{
ViewBag.Message = "You must be logged in to vote on or create new ideas.";
}
//Populate list of IdeaIds and Usernames from IdeaBoardVote table
var ideaBoardVotes = db.IdeaBoardVotes.ToList();
ViewBag.IdeaVoters = new SelectList(ideaBoardVotes, "IdeaId", "Username");
var ideaBoards = db.IdeaBoards.OrderByDescending(i => i.VoteCount).Take(100);
int pageSize = 10;
return View(ideaBoards.ToPagedList(page, pageSize));
}
Here is what I have in my View:
#{bool hasVoted = false;}
foreach (var vote in ViewBag.IdeaVoters)
{
if (vote.IdeaId == idea.Id && vote.Username == User.Identity.Name)
{
hasVoted = true;
}
}
if (!hasVoted)
{
<a href="#Url.Action("IncreaseVote", "IdeaBoard", new { id = idea.Id })" class="btn btn-default btn-sm width-100 margin-bottom text-left">
Vote <span class="glyphicon glyphicon-thumbs-up blue"></span>
</a>
}
What I'm missing that I'm getting the error message?
Probably the column name IdeaId There is something else in the IdeaBoardVotes table
ViewBag.IdeaVoters = new SelectList(ideaBoardVotes, "IdeaId", "Username");
Thank you #Sreenath. Your advise is exactly what I was missing. Here is how I solved this simple issue. In my foreach loop, I was using vote.IdeaId and vote.Username. I changed those to vote.Value and Vote.Text.
if (vote.Value == idea.Id.ToString() && vote.Text == User.Identity.Name)
{
hasVoted = true;
}
Also, changed where the bool was declared so it would be local scope instead of page scope.
Those little changes made the difference. So again, thank you #Sreenath.
I'm filling values to a session's like following to retrive those in _LayoutPartial view
if (userdata != null)
{
Session["userdata"] = new SampleViewModel { FirstName = userdata.UserFirstName, LastName = userdata.UserLastName };
FormsAuthentication.SetAuthCookie(loginmodel.UserName, false);
return RedirectToAction("Dashboard", "Home", new { username = loginmodel.UserName });
}
I want to retrive those values in _LayoutPartial View , So I tried somethin like following
<a class="sa">
(#Session["userdata"] as ProjectName.Models.SampleViewModel).FirstName
(#Session["userdata"] as ProjectName.Models.SampleViewModel).LastName
</a>
But this is not retrieving data properly . In this _LoginPartial I'm not Referencing any model also
You have your parenthesis in the wrong spot, and you need a double set - one for the casting (inner set) and one for the razor execution (outer set). It needs to be
#((Session["userdata"] as ProjectName.Models.SampleViewModel).Name)
I can't find anything to solve my problem in search, and here is my problem:
I'm using ASP.NET MVC 4 and EF 5, I'm trying to get a value from my db, but this db field depends on other var.
In Controller:
public ActionResult Products()
{
ViewBag.lang = "ENG";
DataEntities db = new DataEntities();
ViewBag.Categories = db.Categories;
return View();
}
In Template View:
<ul>
#{
if (ViewBag.Categories != null)
{
foreach (var cat in ViewBag.Categories )
{
<!-- we need in this case "Name_ENG" -->
var title = "Name_" + #ViewBag.lang;
<li>#cat.(title)</li>
<!-- out: cat.ToString() + "(title)" -->
<li>#cat.(#title)</li>
<!-- out: cat.ToString() + "(" + title.ToString() + ")" -->
<li>#cat.#title</li>
<!-- out: cat.ToString() + title.ToString() -->
}
}
}
</ul>
is there a way to get property "Name_ENG" from cat object like #cat.Name_ENG using a string ?
"In this case I'm trying to list al Categories in Products page."
Thanks a lot
No, definitely not in c#. You'd have to use reflection for this to work (and the syntax would be different of course as well).
I think a better option would be to create a method that would retrieve the value based on a string input, like
public T GetValue<T>(string propertyName)
and call that from your view when needed
here is an article from msdn. You can access EF entries properties by name. But at first you need dbContext and second it is wrong to access dbContext from view.
example:
object currentName2 = context.Entry(blog).Property("Name").CurrentValue;
Also, as mentioned in another answer, reflection:
object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance, null);
Try this
<ul>
#{
if (ViewBag.Categories != null)
{
foreach (var cat in ViewBag.Categories )
{
// here you can do something on cat
<text>
<li>#(cat.title)</li>
</text>
}
}
}
</ul>
I personally suggest you to pass the data to the view by parameter. And use #model in the view (strong type view).
I'll explain a quiet better here. I've this method wich returns me some lines of ma table according to a searchstring I informed in my textbox.
public ActionResult Index(string site, string searchString)
{
var user = from m in db.OrderDetails
select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.Order.ClientID.Contains(searchString));
}
if (!String.IsNullOrEmpty(site))
{
user = user.Where(c => c.Order.SiteNumber.Contains(site));
}
return View(user);
}
In the same class, I've an other method which generate a pdf file (all the backend process is set up in a second project include in the first).
public ActionResult PrintOrders()
{
var user = from m in db.OrderDetails
select m;
return this.ViewPdf("Facture", "PrintView", user);
}
This second method, when it generate my pdf file, displays all the entries of my table. I would like that, when I click on my link (on the same page view wich display my table entries) for generate my pdf file, if I did a search before, I juste have fields that match my searchstring (or site string).
How can I implement it ? There is a way do to it ?
Thanks for your help, and sorry for the title which is maybe not too relevant. Also sorry for my english, hope you'll understand my aim.
EDIT INFORMATIONS
After looking, when I set up my PrintOrders() method like my Index() method as follow :
public ActionResult PrintOrders(string searchString, string username)
{
var user = from m in db.OrderDetails select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.Order.ClientID.Contains(searchString));
}
if (!String.IsNullOrEmpty(site))
{
user = user.Where(c => c.Order.SiteNumber.Contains(site));
}
return this.ViewPdf("Facture Krys-Group", "PrintView", user);
}
and set my view like this :
#using (Html.BeginForm("PrintOrders", "Historic", FormMethod.Get))
{
Seach by ID : #Html.TextBox("searchString")
Search by Site : #Html.TextBox("site")
<input type="submit" value="Search" /></p>
}
then it works. But I've already the same form in my view for "Index" instead of "PrintOrders". How can I combine both ?
I am not sure I follow you completely but I think you achieve what you are looking for with the use of partial views. The form you mention can be a partial view that gets rendered into the pdf view and like that you really have one form but displayed in both pages. Hopefully I understood what you were after and this helps you.
I have a javascript that change the value from my dropdown, and when I save the form, the value can't be captured on server side.
Follow bellow some of the code:
<div class="editor-field">
#Html.DropDownListFor(model => model.CategoriaId,
Model.Categorias
.Where(c => c.Id != Model.ContentId)
.Select(c => new SelectListItem {
Selected = c.Id == Model.CategoriaId,
Text = c.Type + " - " +c.Name,
Value = c.Id.ToString()
} ),
"Selecione uma Categoria")
#Html.Hidden("hdnValue", Model.hndCategoriaId) // my hidden value
</div>
Javascript that change the dropdown and the hidden value
function change(item) {
var valueArtigo;
var ddl = document.getElementById('Categoria_CategoriaId');
for (i = 0; i < ddl.options.length; i++) {
if (ddl.options[i].text.toUpperCase().indexOf("ARTIGOS") != -1)
valueArtigo = ddl.options[i].value;
}
document.getElementById("Categoria_CategoriaId").value = valueArtigo;
document.getElementById("Categoria_hdnValue").value = valueArtigo;
}
Getting back on server side, I am trying to save the value on database.
public void UpdateCategoriaForContentItem(ContentItem item, EditCategoriaViewModel model)
{
if ((model.CategoriaId != null)||(model.hndCategoriaId != null)) // both are null
{...}
}
Thanks,
You need to bind the hidden value to the model
#Html.HiddenFor(m=>m.hdnCategoriaId)
or
#Html.Hidden("hdnCategoriaId",Model.hdnCategoriaId,Model)
To set the value of the hidden field on dropdown change event you can simply do
$('#hdnCategoriaId').val(valueArtigo)
Most likly, your problem isn't in javascript but in binding. Try select and submit without javascript to test purposes and look what will be posted in request to server and how will it be mapped on action parameters.