Link to home
Start Free TrialLog in
Avatar of AlHal2
AlHal2Flag for United Kingdom of Great Britain and Northern Ireland

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

Avatar of Kelvin McDaniel
Kelvin McDaniel
Flag of United States of America image

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.
Avatar of AlHal2

ASKER

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.
You're not passing a model in your GET version.
Avatar of AlHal2

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.

@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

SOLUTION
Avatar of kaufmed
kaufmed
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of AlHal2

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.

        [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

Where is the code for your form and your submit button?
Avatar of AlHal2

ASKER

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.
Avatar of AlHal2

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

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of AlHal2

ASKER

Thanks both.