AlHal2
asked on
Output Model to MVC View
I'm using Visual Studio 2017 with C#.
I want a user to input some letters into a textbox. A model maps each letter to a number and returns the total. how can I display the result (Total variable in the model) in a text area in the same view?
Home Controller
Cards View
Model
I want a user to input some letters into a textbox. A model maps each letter to a number and returns the total. how can I display the result (Total variable in the model) in a text area in the same view?
Home Controller
public ActionResult Cards()
{
return View();
}
public ActionResult Cards(CardModel C)
{
C.GetScore(C.Deck);
return View();
}
Cards View
@{
ViewBag.Title = "Cards";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<h2>Cards</h2>
<h2>Please enter a number</h2>
First name: <input type="text" name="Deck"><br>
<textarea id="TextArea1" rows="2" cols="20"></textarea>
<input type="submit" value="Submit">
Model
public class CardModel
{
public string Deck { get; set; }
public int GetScore(string s)
{
int score = 0;
int totalScore = 0;
string individualCard = "";
//loop through each letter in string and convert to a number.
return Total
}
}
ASKER
This line of code
gives this error when I start the project.
This is the controller code.
<textarea id="TextArea1" rows="2" cols="20">@Model.Result</textarea>
gives this error when I start the project.
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=App_Web_apmgbbnv
StackTrace:
at ASP._Page_Views_Home_Cards_cshtml.Execute() in D:\OneDrive\Documents\Tests\BT\WebApplication1\WebApplication1\Views\Home\Cards.cshtml:line 41
This is the controller code.
[HttpGet]
public ActionResult Cards()
{
return View();
}
[HttpPost]
public ActionResult Cards(CardModel C)
{
C.GetScore(C.Deck);
return View(C);
}
I've added the result variable to the model.
Please post the entire View code where that line exists.
You're not passing a model in your GET version.
ASKER
Hi Kelvin,
The user hasn't entered any information when the GET version is called, so I'm not sure which model to pass.
Hi Kaufmed,
Here is the view.
The user hasn't entered any information when the GET version is called, so I'm not sure which model to pass.
Hi Kaufmed,
Here is the view.
@model WebApplication1.Models.CardModel
ViewBag.Title = "Cards";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<h2>Cards</h2>
<h2>Please enter a number</h2>
First name: <input type="text" name="Deck"><br>
<textarea id="TextArea1" rows="2" cols="20">@Model.Result</textarea>
<input type="submit" value="Submit">
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks Kaufmed. I'm no longer getting an error message, but nothing happens when I click submit. I expected it to call this method in the home controller.
In _Layout.cshtml I've added the Cards view, so it appears as one of the options.
[HttpPost]
public ActionResult Cards(CardModel C)
{
C.GetScore(C.Deck);
return View(C);
}
In _Layout.cshtml I've added the Cards view, so it appears as one of the options.
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
<li>@Html.ActionLink("Cards", "Cards", "Home")</li>
</ul>
</div>
Where is the code for your form and your submit button?
ASKER
Here is the controller code.
Here is the score view
Here is the error view. I want to replace the words invalid deck with the error message.
Invalid Deck
Here is the model.
public ActionResult Cards(CardModel C)
{
try
{
C.GetScore(C.Deck);
Models.CardModel NewModel = new Models.CardModel { Deck = C.GetScore(C.Deck).ToString() };
return View("Score", NewModel);
//return View(C);
}
catch (Exception ex)
{
return View("Error", ex.Message);
}
}
Here is the score view
@model WebApplication1.Models.CardModel
<div>
<h4>CardModel</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@*@Html.DisplayNameFor(model => model.Deck)*@
Score:
</dt>
<dd>
@Html.DisplayFor(model => model.Deck)
</dd>
</dl>
</div>
@*<p>
@Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
@Html.ActionLink("Back to List", "Index")
</p>*@
Here is the error view. I want to replace the words invalid deck with the error message.
Invalid Deck
Here is the model.
using System;
namespace WebApplication1.Models
{
public class CardModel
{
public int Result { get; set; }
public string Deck { get; set; }
public string ErrorMessage { get; set; }
public int GetScore(string s)
{
int score = 0;
int totalScore = 0;
string individualCard = "";
bool oneJokerFound = false;
bool twoJokersFound = false;
int number;
if (s == null)
{
return 0;
}
else if (s == "")
{
return 0;
}
for (int i = 2; i < s.Length; i += 3)
{
if (s.Substring(i, 1) != ",")
{
throw new Exception("Deck must consist of two digit card followed by comma");
}
}
s = s.Replace(",", "");
do
{
if (int.TryParse(s.Substring(0, 1), out number))
{
score = int.Parse(s.Substring(0, 1));
}
else if (s.Substring(0, 1) == "T")
{
score = 10;
}
else if (s.Substring(0, 1) == "J" && s.Substring(0, 2) != "JR")
{
score = 11;
}
else if (s.Substring(0, 1) == "Q")
{
score = 12;
}
else if (s.Substring(0, 1) == "K")
{
score = 13;
}
else if (s.Substring(0, 1) == "A")
{
score = 14;
}
else if (s.Substring(0, 2) == "JR")
{
if (twoJokersFound == true)
{
throw new Exception("More than two jokers");
//totalScore = 0;
//break;
}
score = 0;
if (oneJokerFound == true)
{
oneJokerFound = false;
twoJokersFound = true;
}
else
{
oneJokerFound = true;
twoJokersFound = false;
}
}
else
{
throw new Exception("Invalid card");
//totalScore = 0;
//break;
}
switch (s.Substring(1, 1))
//switch (s.Substring(i + 1, 1))
{
case "C":
break;
case "D":
score = score * 2;
break;
case "H":
score = score * 3;
break;
case "S":
score = score * 4;
break;
case "R":
score = 0;
break;
default:
throw new Exception("Invalid card");
//totalScore = 0;
//break;
}
totalScore += score;
individualCard = s.Substring(0, 2);
//individualCard = s.Substring(i, 2);
//if (individualCard != "JR")
//{
s = s.Remove(0, 2);
//}
s.Replace(",,", ",");
if (s.Length > 1 && s.Substring(0, 1) == ",")
{
s = s.Remove(0, 1);
}
if (s.Contains(individualCard) && individualCard != "JR")
{
throw new Exception("Duplicate card " + individualCard);
//totalScore = 0;
//break;
}
} while (s.Length > 0);
if (oneJokerFound == true)
totalScore = totalScore * 2;
else if (twoJokersFound == true)
{
totalScore = totalScore * 4;
}
return totalScore;
}
}
}
As @Kaufmed has alluded to, this won't do anything without an HTML Form element or JavaScript to push the POST to your server endpoint. I've taken the liberty of revising your view to be more modern and use the Helpers since you don't appear to need more flexibility for this example.
Note the TextAreaFor helper on line 14; you might run into some issues if you have needs other than simply binding to this element. If that's the case, take a look at this post for some suggestions on what to do.
@model WebApplication1.Models.CardModel
ViewBag.Title = "Cards";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<h2>Cards</h2>
<h2>Please enter a number</h2>
@using(Html.BeginForm("Cards", "Home", FormMethod.Post))
{
First name: @Html.TextboxFor(m => m.Deck)<br>
@Html.TextAreaFor(m => m.Result, 2, 20)
<input type="submit" value="Submit">
}
Note the TextAreaFor helper on line 14; you might run into some issues if you have needs other than simply binding to this element. If that's the case, take a look at this post for some suggestions on what to do.
ASKER
I'm getting these error messages from your code.
Error CS1061 'HtmlHelper<CardModel>' does not contain a definition for 'TextboxFor' and no extension method 'TextboxFor' accepting a first argument of type 'HtmlHelper<CardModel>' could be found (are you missing a using directive or an assembly reference?)
Error CS1501 No overload for method 'TextAreaFor' takes 3 arguments
However, this code works.
I'm also trying to handle errors. My controller method looks like this. How should I amend the Cards view to display the exception message.
Error CS1061 'HtmlHelper<CardModel>' does not contain a definition for 'TextboxFor' and no extension method 'TextboxFor' accepting a first argument of type 'HtmlHelper<CardModel>' could be found (are you missing a using directive or an assembly reference?)
Error CS1501 No overload for method 'TextAreaFor' takes 3 arguments
However, this code works.
@using (Html.BeginForm("Cards", "Home"))
{
<input type="text" name="Deck"><br>
<textarea id="TextArea1" rows="2" cols="20">@Model.Result</textarea>
<input type="submit" value="Submit">
}
I'm also trying to handle errors. My controller method looks like this. How should I amend the Cards view to display the exception message.
[HttpPost]
[HandleError]
public ActionResult Cards(CardModel C)
{
string exmsg = "";
try
{
C.GetScore(C.Deck);
Models.CardModel NewModel = new Models.CardModel { Deck = C.GetScore(C.Deck).ToString() };
return View("Score", NewModel);
//return View(C);
}
catch (Exception ex)
{
exmsg = ex.Message;
ModelState.AddModelError("General error", exmsg);
return View();
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks both.
Open in new window
Next, add an int property to CardModel that will be used to show the result of the GetScore() function call. For the sake of discussion I've added one named Result. Notice that I didn't change the return type of GetScore(). However, in this example it could be void instead of returning int.
Open in new window
Finally, update your View to use the CardModel class as its bound Model. Also, set the View to show the value of the new property Result in the textarea element.
Open in new window
And you should be good to go. I did this from memory on my phone so you might have to tweak it a bit. For example, make sure your namespaces are correct for the CardModel reference in the View. Also, for the code you've provided you need to add a Form element. Of course you could use JavaScript but I don't see any evidence of that being used here.