Modify existing object in ASP.NET - c#

I have some problem with my ASP.NET MVC application. How can I modify an existing object created previously in different ActionResult?
I created object in this action:
public ActionResult getLogin(AccountViewModel accountViewModel)
{
Account account2 = de.Accounts.FirstOrDefault(a => a.Username == accountViewModel.Account.Username);
PasswordReminder.PasswordReminder reminder = new PasswordReminder.PasswordReminder();
reminder.showQuestion(account2.Username);
return View("Question", reminder);
}
And I want to add an attribute to the existing reminder object by this ActionResult
#model PasswordReminder.PasswordReminder
#{
Layout = null;
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Question</title>
</head>
<body>
<div>
#Model.questionReminder
#using (Html.BeginForm("Answer", "Account", FormMethod.Post))
{
#Html.TextBoxFor(a => a.reminderAnswer)
<input type="submit" value="Send" />
}
</div>
</body>
</html>
So in my View "Answer" in attribute "reminderAnswer" I entered value but questionReminder is null, so this must be a new object.. Thanks for all help

If I have understood your question correctly, in order to achieve what you are after, the PasswordReminder object that you are using as your Model, must be persisted in the getLogin action, and then passed back separately as the model from your action that feeds your Answer view (but I recommend to use a ViewModel as an abstraction over the previous PasswordReminder object for security)
This would insure you are referencing the previously instantiated PasswordReminder object in your Answer view, in order to modify the value of reminderAnswer property.

Related

Reusing the same html code as a partial view 'n' number of times in the same index.cshtml page

I have a partial view which renders a visual form made entirely in HTML with some .css. What I want to do is reuse this same form in the same page [n] number of times. In my HomeController class I am instantiating the model as such:
public IActionResult Index()
{
List<Foo> foos = new List<Foo>();
foos.Add(new Foo { Name = "John" });
foos.Add(new Foo { Name = "Dave" });
foos.Add(new Foo { Name = "Sean" });
foos.Add(new Foo { Name = "Alan" });
return View(foos);
}
Then in my index.cshtml I am iterating using the list I receive from my controller and generating a partial view based on the length of my list
#model List<HelloWorld.Models.Foo>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Foo</title>
<link rel="stylesheet" href="~/foo/styles.css" />
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="~/foo/FooActions.js"></script>
</head>
<body>
#{
foreach (Foo foo in Model)
{
ViewData["Name"] = foo.Name;
<partial name="_Foo" view-data="ViewData" />
}
}
</body>
</html>
This is how I have my partial view set up:
<script type="text/javascript">
init('#ViewBag.Name');
</script>
<div class="foo-background">
<section>
<div>
<span class="score-text" id="redText">0</span>
</div>
<div class="green-bar"></div>
<div class="red-bar"></div>
<div>
<span class="bonus-score-text" id="greenText">0</span>
</div>
</section>
<section>
<div class="alphanumeric-display">
<p class="alphanumeric-display-text" id="textLine1">Text</p>
<p class="alphanumeric-display-text" id="textLine2">Text</p>
<p class="alphanumeric-display-text" id="textLine3">Text</p>
</div>
<div>
<span class="person-grade-text" id="goldText">0</span>
</div>
</section>
</div>
This form pulls data from a local database and displays data based on the person its tied to. The data shows up fine if its only displaying data of one person in the page. I'm using JavaScript to grab either the class or the id of these html elements and update their respective data.
But now what its doing is showing all the forms side-by-side, only, the data is wrong. None of the forms show the data from the table as they appear in the database. Upon closer inspection looks like it has a problem where each of these forms cant have the same class or ids. I'm getting this in error in all places where I have class or id elements
id attribute value must be unique: Document has multiple static
elements with the same id attribute: textLine1
Its the same error for each of my html elements.
Can someone help me understand what I am doing wrong? What can I do in order to get this to work properly?

partial view form submits object bound to parent view model instead of its own model

I have the following bits from my test application.
A method used for posting the data from a partial view.
public IActionResult AddPayor(Payor newPayor)
{
if (ModelState.IsValid)
{
mvSrv.SaveOnePayor(newPayor);
return RedirectToAction("Index", "Payor");
}
else
{
return View();
}
}
And index cshtml view where I want to have a list of item plus the ability to add more.
Notice the model class PayorView; it contains a list of payors to use in the ViewPayor view and a single payor to use in the AddPayor view. I do it this way so that the AddPayor can have an object passed down even when the list is empty. Earlier I tried to have only the list as the model but sending the [0] element failed when list was empty.
#addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
#model FSA_Tracker.ViewModels.PayorView
#{
Layout = "_Layout";
}
<partial name="ViewPayor" for="payors" />
<partial name="AddPayor" for="payor" />
The partial view for AddPayor is just an input form. The model object is pass down from the parent view.
#addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
#model FSA_Tracker.Models.Payor
<fieldset>
<form asp-action="AddPayor" method="post">
<div asp-validation-summary="ModelOnly" class="input-validation-error"></div>
<div id="formContainer">
<p>
<label asp-for="Name"></label>
<input asp-for="Name" />
<span asp-validation-for="Name"></span>
</p>
<p>
<button type="submit">Add Payor</button>
</p>
</div>
</form>
</fieldset>
My problem is that the newPayor argument in my post method does not get initialized, but rather what gets initialized is the PayorView.payor property in the parent view model object. So I can make it work if I change to
and I extract the payor from there.
Is there a way to prevent my partial view from binding its object to the parent view model? Preferably from the parent view.
Thanks
try passing in the payor model into your partial view like:
<partial name="ViewPayor" model="#Model.Payor" />
Got it. I needed to instantiate and pass the new new model into the partial. Now I see what Matthias L meant. I just didn't know I could go to a different namespace than the one in the declaration section. This will give the partial view a new Provider object rather than an attribute from the parent view.
#{
var provider = new FSA_Tracker.Models.Provider();
<partial name="AddProvider" model="#provider" />
}

Cant find page after POST redirect C#

I go to a View, submit data via POST, but the redirect cannot find the Controller method. What am I doing wrong here? After submitting the form I get:
404 error: cannot find page. URL is: http://localhost:52008/InternalController/UpdateCardFormPost
Snippet from InternalController.cs:
public ActionResult UpdateCardFormView()
{
var CardToUpdate = new CardView();
return View(CardToUpdate);//return implementation of Cards.cshtml with the empty model that was passed to it
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UpdateCardFormPost(CardView c)
{
CardModelIO.WriteCard(c);//#TODO: IMPLEMENT
return View("CardDetailView", c);
}
UpdateCardFormView.cshtml (the view with the form I am submitting):
#using LeanKit.API.Client.Library.TransferObjects
#model CardView
<!DOCTYPE html>
<html>
<!--Form used to change a card
STARTING DISPLAY called by in Internal/UpdateCardFormView
ENDING DISPLAY (post) called by UpdateCardForm in InternalController a specified below-->
<head>
</head>
<body>
#Html.BeginForm("UpdateCardFormPost", "InternalController", FormMethod.Post)
#Html.TextBoxFor(c => c.AssignedUserName);
<input type="submit" value="Submit Changes" />
</body>
</html>
Heres the CardDetailView.cshtml (the view I should be redirected to):
#using LeanKit.API.Client.Library.TransferObjects
#model IEnumerable<CardView>
<!--used for displaying an individual card in detail view
referenced in UpdateCardFormPost() method of Internal controller-->
<!DOCTYPE html>
<html>
<head>
</head>
<body>
CardView j = Model;
<p>j.AssignedUserId</p>
</body>
</html>
You've specified the controller name as InternalController but it's probably just called "Internal".
Try changing
#Html.BeginForm("UpdateCardFormPost", "InternalController", FormMethod.Post)
to
#Html.BeginForm("UpdateCardFormPost", "Internal", FormMethod.Post)
you are missing closing form tag
you should do it like
using (#Html.BeginForm("UpdateCardFormPost", "InternalController", FormMethod.Post))
{
...
}
#using(Html.BeginForm())
{
#Html.TextBoxFor(c => c.AssignedUserName);
<input type="submit" value="Submit Changes" />
}

Verifying credentials without leaving view

I've got a user login page that I want to check if the inserted credentials are correct. Here's the controller:
EDITED:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SustIMS.Models;
namespace SustIMS.Controllers
{
public class MainController : Controller
{
public static string userName;
public static string password;
public ActionResult Index()
{
getCredentials();
if (Authenticate(userName, password))
{
return View();
}
ModelState.AddModelError("", "Could not authenticate");
return Redirect("../Home");
}
public void getCredentials()
{
if (Request["username"] != null && Request["password"] != null)
{
userName = Request["username"].ToString();
password = Request["password"].ToString();
}
}
}
}
Everything is OK if the inserted credentials are correct: the Authenticate function verifies that and if it returns true, the ActionResult returns the View.
However, if they are not correct, I set it to return null, going to a blank page instead.
I want it to stay on the same page and display some kind of message to the user informing that the credentials aren't correct (by showing a div, calling a javascript function with a popup window, ..., I don't really know).
How can I do that?
Thanks
EDIT
Here's my view:
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>#ViewBag.Message</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
</head>
<body>
<div id="outer-limit">
<div class="logo-main">
<a href="../Home/Index">
<img class="displayed" src="../../Images/logo.png" alt="SustIMS" /></a>
</div>
<section class="container">
#Html.Partial("LoginForm")
#Html.ValidationSummary()
</section>
</div>
</body>
</html>
And the partial LoginForm:
<div class="login">
<h1>#ViewBag.Login</h1>
<form method="get" action="../Main/Index">
<p>
<input type="text" name="username" value="" placeholder="Username" maxlength="30"></p>
<p>
<input type="password" name="password" value="" placeholder="Password" maxlength="25"></p>
<br />
<br />
<p class="submit">
<input type="submit" onclick="Refresh()" name="commit" value="Login"></p>
</form>
</div>
doing something like this should work. Checking the ModelState can/will validate required fields via Attributes on your view (if you've implemented them) otherwise you can manually take care of that in your action. Adding the model error before returning the view will cause the error to display on the page after it reloads. Upon successful authentication, we're redirecting to another Action.
public ActionResult Index(LoginModel model) {
if (ModelState.IsValid) {
if (AuthenticateUser(model)) {
return RedirectToAction("LoggedIn");
} else {
ModelState.AddModelError("", "Could not authenticate"); //or better error
}
}
return View(model);
}
be sure to also add an #Html.ValidationSummary() to your view to display the error message returned.
You should be able to tailor the above code to work with your methods, but ultimately, I would recommend strongly typing your views and passing a model back through a post.
EDIT
Redid my example based on your code above, rather than a general example
public ActionResult Index()
{
getCredentials();
if (Authenticate(userName, password))
{
return View();
}
ModelState.AddModelError("", "Could not authenticate");
return View();
}
My recommendation would be to RedirectToAction after successful authentication, rather than returning the same view.
One way to do that :
public ActionResult Index(string url)
{
getCredentials();
if (Authenticate(userName, password))
{
return View();
}
else
{
TempData["ErrorMessage"]="Wrong Credential";
return Redirect(url);
}
}
}
Then in your view Show the message in a div if it's not empty
#if(TempData["ErrorMessage"] != null)
{
<div class='alert alert-success alert-dismissable' >
#TempData["ErrorMessage"]
</div>
}
I believe you have wrong idea how ASP.NET MVC works. If you submit form, the whole new request is made, and its response will be shown - that is, you must return something to display back yo user - typically view. Never return as ActionResult. In your case, you return View() in both cases, just give it different data to display - succeess message or error message for example. You can use strongle typed model for this, or ViewBag - take a look at some tutorials.
If you want user to "stay on the same page" if credentials are wrong, you need some kind of ajax validation. ASP.NET MVC supports this also, take a look at http://msdn.microsoft.com/en-us/library/gg508808(vs.98).aspx

Form Values from Model Not Updating in View After Post

I believe I'm missing something quite trivial here, but I'm not spotting it. I have a Post method, which modifies a Model property. I then want that model property to reflect the new property value. So here are the pieces:
Controller:
[HttpPost]
public ActionResult Index(HomeModel model)
{
ModelState.Clear(); //Didn't help
model.MyValue = "Hello this is a different value";
return View(model);
}
Model:
public class HomeModel
{
[Display(Name = "My Message")]
public string MyValue { get; set; }
}
View:
#model MyApp.Models.HomeModel
#{
ViewBag.Title = "My MVC App";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Home"))
{
<h5>Hello</h5>
<input id="SendMessage" type="submit" value="Send Message"/>
#Html.LabelFor(m => m.MyValue)
}
</div>
</body>
</html>
When I debug the controller I can see the updated model, but my LabelFor always has the Display attribute as opposed to the value I provided of "Hello this is a different value". What am I missing here that this label is not updated?
#Html.LabelFor displays your property name (or the name defined in your DisplayAttribute), whereas #Html.DisplayFor displays your property content. If your want "Hello this is a different value" displays, replace #Html.LabelFor by #Html.DisplayFor
The html helper look at the ModelState when binding their values and then in the model.
So if you intend to modify any of the POSTed values inside your controller action make sure you remove them from the model state first:
ModelState.Remove("PropertyName");
Read this MVC 3 - Html.EditorFor seems to cache old values after $.ajax call
That's the purpose of LabelFor, display the property name. Either use EditorFor or just access the model property directly inside a label tag it to your view
<h5>Hello</h5>
<input id="SendMessage" type="submit" value="Send Message"/>
<label>#Model.MyValue</label>

Categories

Resources