Output Model to MVC View

AlHal2
AlHal2 used Ask the Experts™
on
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
public ActionResult Cards()
        {
            return View();
        }
        public ActionResult Cards(CardModel C)
        {
            C.GetScore(C.Deck);
            return View();
        }

Open in new window


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">

Open in new window


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
}
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
First, update your controller to return the Model so it will be bound to the View.

public ActionResult Cards()
{
        return View();
}

public ActionResult Cards(CardModel C)
{
        C.GetScore(C.Deck);
        return View(C);
}

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.

public class CardModel
{
        public string Deck { get; set; }

        // new property
        public int Result { 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.

           // set Result equal to the Total
           Result = totalScore;
           return totalScore;
        }
}

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.

@model 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">

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.

Author

Commented:
This line of code

<textarea id="TextArea1" rows="2" cols="20">@Model.Result</textarea>

Open in new window


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

Open in new window


This is the controller code.
        [HttpGet]
        public ActionResult Cards()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Cards(CardModel C)
        {
            C.GetScore(C.Deck);
            return View(C);
        }

Open in new window

I've added the result variable to the model.
Please post the entire View code where that line exists.
OWASP Proactive Controls

Learn the most important control and control categories that every architect and developer should include in their projects.

ǩa̹̼͍̓̂ͪͤͭ̓u͈̳̟͕̬ͩ͂̌͌̾̀ͪf̭̤͉̅̋͛͂̓͛̈m̩̘̱̃e͙̳͊̑̂ͦ̌ͯ̚d͋̋ͧ̑ͯ͛̉Glanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015

Commented:
You're not passing a model in your GET version.

Author

Commented:
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.

@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">

Open in new window

ǩa̹̼͍̓̂ͪͤͭ̓u͈̳̟͕̬ͩ͂̌͌̾̀ͪf̭̤͉̅̋͛͂̓͛̈m̩̘̱̃e͙̳͊̑̂ͦ̌ͯ̚d͋̋ͧ̑ͯ͛̉Glanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015
Commented:
Pass a new, empty model.

return View(new WebApplication1.Models.CardModel());

Open in new window

Author

Commented:
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.

        [HttpPost]
        public ActionResult Cards(CardModel C)
        {
            C.GetScore(C.Deck);
            return View(C);
        }

Open in new window


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>

Open in new window

ǩa̹̼͍̓̂ͪͤͭ̓u͈̳̟͕̬ͩ͂̌͌̾̀ͪf̭̤͉̅̋͛͂̓͛̈m̩̘̱̃e͙̳͊̑̂ͦ̌ͯ̚d͋̋ͧ̑ͯ͛̉Glanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015

Commented:
Where is the code for your form and your submit button?

Author

Commented:
Here is the controller code.
        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);
            }

        }

Open in new window


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>*@

Open in new window


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;
   
        }
    }
}

Open in new window

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.

@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">
}

Open in new window


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.

Author

Commented:
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.
@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">
    }

Open in new window


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();

            }

        }

Open in new window

I really want to help, but it's clear that you're just getting started and haven't gotten the basics fundamentals of ASP.NET MVC down yet.
- @Html.TextboxFor should be @Html.TextBoxFor. IntelliSense should have told you that.
- @Html.TextAreaFor --> just pass a null for the 4th parameter. IntelliSense and the link I provided should have told you that.

A few things to consider:
- These Q&A forums on EE assume that you've got those fundamentals and just need a nudge in the right direction.
- What you're asking for is a bit beyond the scope of the help we can efficiently provide in the open forums here on EE.
- This back and forth trial and error is really frustrating for everyone -- to give you the level of support you're really asking for, we would need to download and work directly in your VS solution.

Please note that at any time, you can, however, engage with one (or more) of the Experts that accept Live sessions. Typically, they'll be able to assist in the level of detail that you need. This is not a plug for myself because I don't do EE Gigs.

Good luck!

Author

Commented:
Thanks both.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial