Why can't I use an iteration variable in a LoginView? - asp.net

I am building a .NET MVC app that has a page with a list of delete buttons, one for each item in a list. The problem I'm having is that the foreach variable "item" is not visible inside the LoginView, which results in the following error:
Compiler Error Message: CS0103: The name 'item' does not exist in the current context
Below is a simplified version of the view. The error occurs at the "new {id=item.Id}" in the LoggedInTemplate - the reference to "item" in the ActionLink works fine:
<% foreach (var item in Model) { %>
<%= Html.ActionLink("Item", "Details", new { id = item.Id })%>
<asp:LoginView runat="server">
<LoggedInTemplate>
<% using( Html.BeginForm( "Delete", "Items", new {id=item.Id}, FormMethod.Post))
{ %>
<input type="submit" value="Delete" runat="server" />
<% } %>
</LoggedInTemplate>
</asp:LoginView>
<% } %>
To clarify the problem is not that the Model has not been successfully passed to the View. The Model is visible from both inside and outside the LoginView. The foreach loop as no problem in iterating through the items in the Model (which is a List). The problem is that the iteration variable "item" is not accessible from within the LoginView - though the original Model is.
Is there any way to pass "item" through to the LoginView's templates? Or is building LoginViews within a foreach loops the wrong way of doing things?
Is there a scoping rule that prevents using local variables within controls - perhaps because the control is rendered at a different time to the main page?

With ASP.NET MVC you really shouldn't use user/custom controls, so if you omit the <asp:LoginView/> and write a line of code to check if the user is authenticated, you are good to go.
Instead of your current code:
<asp:LoginView runat="server">
<LoggedInTemplate>
<div>Show this to authenticated users only</div>
</LoggedInTemplate>
</asp:LoginView>
Just use an if-statement and the value of Request.IsAuthenticated:
<% if (Request.IsAuthenticated) { %>
<div>Show this to authenticated users only</div>
<% } %>

Are you passing the Model to the view and are you also inheriting from the model within that view?
So if this is a View then in your C# code you need to return the list of items like return View(listofitems);
If this is a partial view then <% Html.RenderPartial("MyPartial", listofitems) %>
And in the view you need to
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IQueryable<ListOfItems>>" %>
If all that is in place then it should work no probs.

<% foreach (var item in Model) { %>
<%= Html.ActionLink("Item", "Details", new { id = item.Id })%>
<%= if( Request.IsAuthenticated ) {
using( Html.BeginForm( "Delete", "Items", new {id=item.Id}, FormMethod.Post))
{ %>
<input type="submit" value="Delete" runat="server" />
}
} %>
<% } %>
There is no need to use the LoginView, its not really giving you anything. Use something like the above instead.
Alternatively, you can move the decision of whether to show the delete option for the specific item into the controller, so instead of doing if( Request.IsAuthenticated ) you would do if( item.ShowDelete ) ... assuming item's type is a view model. Another option is to use an extension method for the same, item.ShowDelete(). I prefer the earlier, because there might be logic associated to deciding whether to show delete for a given item, so its better to not have it in the controller or a related logic.

Related

Using Request.QueryString in ASP.NET Embedded Code Block

I am attempting to pass a parameter from one file to another via the URL after a button is clicked. These are written with Express.js (index.ejs to items.ejs).
As it stands currently I am setting the URL parameter in a defined Javascript function:
function loadItems(page, subcategory) {
window.history.pushState(null, null, "?subcat=" + subcategory) //param set
$('#mainContent').load(page);
}
where subcategory is the changing variable.
From there I am trying to read this parameter during an ASP.NET function written in embedded code blocks.
<% if(items[i].subcategory === Request.QueryString["subcat"].Value) { %> //get param
<% if (items[i].status === "Supported") { %>
<tr class="success">
<td>Edit</td>
<td id="item name"><%= items[i].name%></td>
<td id="subcat name"><%= items[i].subcategory%></td>
<td id="item status"><%= items[i].status%></td>
<td id="item desc"><%= items[i].description%></td>
</tr>
However I am met with an error which states Request is not defined and a callback to the above if statement. It is my understanding that on the ASP.NET side of things, Request.QueryString is a part of System.Web.HttpContext.Current.
How would I go about including this into my code blocks so that I am able to pull the parameter from the URL? Or, if this is not the way to be looking at this problem, how should I go about it?
My advice would be to use code behind. Embedded code blocks are an old-school throwback from the asp days. But if you must, then you should be able to do something like this:
<%# Page Language="VB" %>
<script run=server>
Protected Function GetSubcat() As String
Return Request.QueryString["subcat"].Value
End Function
</script>
<form id="form1" runat="server">
Subcat value is <% =GetSubcat()%>.
</form>

asp.net mvc2 dropdownlistfor

I want to create a dropdownlist in my asp.net MVC2 view and I am following code:
foreach (var whiteout in Model)
{
%>
<tr>
<td>
<%= whiteout.Field.NiceName%>
<% Html.DropDownListFor("anyname", Model); %>
<%
}
}
%>
but I am getting error that second parameter is not correct. Second parameter is a list. Here is how Model is declared at the top of partial view:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<EnviroTracker.Entities.Whiteout>>" %>
Please suggest how to fix this?
A DropDownListFor helper takes a SelectList as second argument and a lambda expression to a simple property as first:
<%= Html.DropDownListFor(
x => x.SomeProperty,
new SelectList(Model.SomeList, "ValueProperty", "TextProperty")
) %>
If you want to use the weakly typed DropDownList helper you could manually specify the name of the property it will be bound to but the second argument should still be a SelectList:
<%= Html.DropDownList(
"SomeProperty",
new SelectList(Model.SomeList, "ValueProperty", "TextProperty")
) %>

How to make If statements in Databound ListView

I have a ListView with many advanced controls and html tags. ListView is bound to collection of profiles when first profile in collection is current profile. current profile has few differences from other profiles ie. flash embed, js and some other stuff. I can access inside of my ListView Container.DataIndex property which gives me 0 as first item in index but i'm unable to use inline If statements like so
<% If Container.DataIndex = 0 Then %>
do stuff
<% EndIf %>
this is because i must place pound to access databound item but neither this
<%# If Container.DataIndex = 0 Then %>
do stuff
<% EndIf %>
How can i make inline If ?
Try this:
<% if (DataBinder.Eval(Container, "DataItemIndex")) { %>
do stuff
<% } else { %>
do other stuff
<%} %>
Here is a small summary of the inline aspx tags:
http://naspinski.net/post/inline-aspnet-tags-sorting-them-all-out-%283c25242c-3c253d2c-3c252c-3c252c-etc%29.aspx
But i would recommend to use ListView.ItemDataBound. It is less error-prone and more readable in codebehind.
Did you mean IIF? IIF - Returns one of two objects, depending on the evaluation of an expression.

custom controls and query string(asp.net)

How to call a custom control when query string is changed?
My example not work?Why?
<% if(Convert.ToInt32(Request.QueryString["id"])==6){ %>
<answer:answer_n id="give_me_top_five_news" runat="server" />
<%} %>
<% if(Request.QueryString["do"]=="registracija"){
Page.Header.Title = "HHHHH";
%>
<reg:f_reg id="custom_controls_for_registration" runat="server" />
<%} %>
Changed in what fashion? Anytime you load the page with a new URL and query string, the page will be loaded for the first time. You would have to save the info you wanted to store in the Session (for example) and then in the Page_Load event check the query string vs the Session variable to see if they are the same or different.
There may be different ways to do it, but that's what comes to mind off the cuff.

Validating dynamically created fields in ASP.NET MVC

I have the following form in an ASP.NET MVC view:
<%= Html.ValidationSummary() %>
<% var fields = ViewData.Model; %>
<% using (Html.BeginForm("Dynamic", "Candidate")) { %>
<% foreach (var field in fields) { %>
<label for="<%= field.FieldName %>"><%= field.FieldName %></label>
<%= Html.TextBox(field.FieldName, field.Value, new { #class = "short" }) %>
<% } %>
<a class="button green" onclick="$('form').submit(); return false;">Submit</a>
<% } %>
I have a single controller action that loads this form as well as accepts the post, it looks like this:
public ActionResult Dynamic() {
var fields = DataProvider.Candidates.GetAllDynamicFields();
if (Request.HttpMethod == "POST") {
fields.ForEach(f => f.Value = Request[f.FieldName]);
var validation = DataProvider.Candidates.SaveDynamicFields(fields);
if (validation.IsValid)
return RedirectToAction("Index");
ViewData.ModelState.AddErrorsFromValidationResult(validation);
}
return View(fields);
}
My problem is that if any of the validators fail (i.e. the validation object contains errors) then I get an error on view rendering because ViewData.ModelState doesn't contain any keys. Where am I going wrong here? Any clues?
Figured it out. ViewData.ModelState is populated by the params in the response object. So with a dynamically created form you don't know exactly what was passed in the post. So I just recreate my ModelState on the fly:
fields.ForEach(f => ViewData.ModelState.Add(f.FieldName ...
And then we're all good...when the validation is run on the view it can find all the keys in the ModelState and no exceptions...works like a charm.
Asp.Net C# MVC Dynamic Forms (Changing Dom structure and getting data on the server)

Resources