I created a repository and now i want to use a foreach to add multiple items to the page but its giving me a error. My objective is: when there is no items in the page it will show a message but if the page have items will show a different message and the items. The code is the following:
Controller:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Treino1.Models;
namespace Treino1.Controllers
{
public class DespesasController : Controller
{
public IActionResult Index()
{
List<Despesa> despesas = RepositorioDespesas.Despesas;
return View(despesas);
}
[HttpGet]
public IActionResult NovaDespesa()
{
return View();
}
[HttpPost]
public IActionResult NovaDespesa(Despesa despesa)
{
if (ModelState.IsValid)
{
RepositorioDespesas.AddDespesa(despesa);
return View("DespesaConfirmada", despesa);
}
return View();
}
}
}
Repository
using System.Collections.Generic;
namespace Treino1.Models
{
public static class RepositorioDespesas
{
private static List<Despesa> despesas = new List<Despesa>();
public static List<Despesa> Despesas
{
get { return despesas; }
}
public static void AddDespesa (Despesa newDespesa)
{
despesas.Add (newDespesa);
}
}
}
#{
ViewData["Title"] = "Despesa Confirmada";
}
#model List<Treino1.Models.Despesa>
#if (Model.Count== 0)
{
<h1>Sem Despesas...</h1>
}
else
{
<h1>Despesas!</h1>
#foreach (Treino1.Models.Despesa d in Model)
{
<div class="card bg-secondary border-dark">
<div class="card-body">
<b>Nome da Despesa: </b> #d.NomeDespesa
<b>Quantidade: </b> #d.Quantidade
<b>Valor: </b> #d.Valor
<b>Categoria: </b> #d.Categoria
<b>Pago? </b>
#if (d.Pago)
{
#:Sim
}else
{
#:Não
}
</div>
</div>
}
}
<div>
<a asp-action="NovaDespesa">Nova Despesa</a>
</div>
I think the error is something about the Model.Count==0 but i dont know how to solve.
The error is this:
The data model in the DespesaConfirmada strongly typed view is defined as #model List<Treino1.Models.Despesa>, but when it rendered from the public IActionResult NovaDespesa(Despesa despesa) action method the single Treino1.Models.Despesa object is passed. Try to use like below:
public IActionResult NovaDespesa(Despesa despesa)
{
if (ModelState.IsValid)
{
RepositorioDespesas.AddDespesa(despesa);
// Obtain corresponded records from the repository and pass to the view.
return View("DespesaConfirmada", RepositorioDespesas.Despesas());
}
return View();
}
Related
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Csharp_ASPNetCore.Pages.Shared
{
public class ExampleController : Controller
{
public ExampleController()
{
}
[HttpGet]
[Route("/example/")]
public IActionResult Index()
{
return View();
}
[HttpPost]
[Route("/example/")]
public IActionResult Index(string someValue)
{
string buttonClicked = "";
if (HttpContext.Request.Form.ContainsKey("btnOne"))
{
buttonClicked = "btnOne";
int a = 1;
int b = 2;
int c = a + b;
// return View("AAAAAA");
}
else if (HttpContext.Request.Form.ContainsKey("btnTwo"))
{
buttonClicked = "btnTwo";
}
return View("Index");
}
}
}
The last View("Index") command doesn't work, returning this error:
"An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Index' was not found. The following locations were searched: /Views/Example/Index.cshtml /Views/Shared/Index.cs
Following I report the Index.cshtml where there are the buttons (the name of the controller is ExampleController.cs). Thanks!
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<div>
<form asp-controller="example" asp-action="Index">
<label>Value:</label>
<input name="someValue" type="text" maxlength="10"/>
<button name="btnOne" type="submit" class="btn btn-default">Click One</button>
<button name="btnTwo" type="submit" class="btn btn-default">Click Two</button>
</form>
</div>
I'm using this class :
public class SteamGet
{
public delegate ActionResult ResultDone(List<Steam> List);
public event ResultDone OnResultDone;
public void Get()
{
Debug.Write("Result Received !");
using (WebClient client = new WebClient())
{
string data = client.DownloadString("http://api.steampowered.com/ISteamApps/GetAppList/v0001/");
JObject steamobject = JObject.Parse(data);
var rslt = steamobject.SelectToken("applist").SelectToken("apps");
var objd = JsonConvert.DeserializeObject<ObjectResult>(rslt.ToString());
OnResultDone(objd.MyList);
}
}
}
And my home controller looks like this :
public class HomeController : Controller
{
// GET: Home
protected SteamGet Getter = new SteamGet();
public ActionResult Index()
{
Getter.OnResultDone += Getter_OnResultDone;
Task.Run(() => Getter.Get());
return View();
}
private ActionResult Getter_OnResultDone(List<Models.Steam> List)
{
return View("ViewTest",List);
}
}
so as you can see i'm calling the Get() Method then Returning the View , when the Event OnresultDone Raised i want to Call another View or refreshing the home view
my home view :
#using TemplateAspTest.Repository
#model List<TemplateAspTest.Models.Steam>
#{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/_Main.cshtml";
}
<section id="intro" class="main">
<span class="icon fa-diamond major"></span>
<h2>Test one section ! </h2>
<p>
test done !
</p>
<ul class="actions">
#{
if (#Model == null)
{
<li>waiting ....</li>
}
else
{
<li>ViewBag.Message;</li>
#Model[0].Name;
}
}
</ul>
</section>
EDIT :
i'am Returning View and waiting for a event to be raised i want to call another view when the even is raised
I am trying to learn how to use TryUpdateModel but I cannot get it to work, you can find my code below:
Controller Side
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace EFW6.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
private WorkFlowContext context = new WorkFlowContext();
public ActionResult Index()
{
return View();
}
[HttpPost]
public string UploadFile(FormCollection form)
{
Files file = new Files();
if (TryUpdateModel(file, form.ToValueProvider()))
{
return "True " + file.filePath;
}
else
{
return "False";
}
}
}
}
View Side
#{
ViewBag.Title = "index";
}
<h2>#Model</h2>
<form method="post" action="Home/UploadFile">
<input type="text" name="filePath">
<input type="submit">
</form>
Model Class
class Files
{
public string filePath;
}
When I return the value of the file path it returns nothing while it returns the value True for as a result for the operation.
the problem is that you I am using field instead of property in the Files Class
You have to change it to be like this
class Files
{
public string FilePath { get; set; }
}
I don't understand why ModelState.isValid give me in all the ways. I set something in the email returns true and I pùt empty field, it returns true too. My question ism, what do I have to do to return true when the field is empty and nothing whn I wrote the email?
I have the next view file:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div style="padding-top:5px;clear:both;"></div>
<% using (Html.BeginForm()) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Email usuario</legend>
<div class="editor-field">
<%: Html.TextBoxFor(m => m.Email) %>
<%: Html.ValidationMessageFor(m => m.Email) %>
</div>
<input type="submit" value="Enviar Email" />
</fieldset>
<% } %>
<div style="padding-top:5px;clear:both;"></div>
</asp:Content>
The Controller is:
//
// GET: /Account/EmailRequest
public ActionResult EmailRequest()
{
return View();
}
[HttpPost]
public ActionResult EmailRequest(string email)
{
if (ModelState.IsValid)
{
// save to db, for instance
return RedirectToAction("AnotherAction");
}
return View();
}
My model class is:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Security;
namespace PortalClient.Models
{
public class EmailRequest
{
[Required(ErrorMessage = "required")]
public string Email { get; set; }
}
}
Change the signature of your post action from string email to EmailRequest model and then check the state. e.g.
[HttpPost]
public ActionResult EmailRequest(EmailRequest model)
{
if (ModelState.IsValid)
{
// save to db, for instance
return RedirectToAction("AnotherAction");
}
return View();
}
You need to bind a view model to your view.
Change your EmailRequest model to something more descriptive like:
public class EmailRequestViewModel
{
[Required(ErrorMessage = "Required")]
public string Email { get; set; }
}
Your get action method would look something like:
public ActionResult EmailRequest()
{
EmailRequestViewModel viewModel = new EmailRequestViewModel();
return View(viewModel);
}
Your post action method:
public ActionResult EmailRequest(EmailRequestViewModel viewModel)
{
// Check for null view model
if (!ModelState.IsValid)
{
return View(viewModel);
}
// Do whatever you need to do
return RedirectToAction("List");
}
And then your view. Please excuse the ASP.NET MVC 4 code, MVC 2 is prehistoric :) This is just part of your view:
#model YourProject.ViewModels.EmailRequestViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Email)
#Html.ValidationMessageFor(x => x.Email)
}
I hope this helps.
you need to bind your model with binder first to have ability to chek it by Modelstat.IsValid
public ActionResult EmailRequest()
{
EmailRequest email = new EmailRequest();
TryUpdateModel(email);
if (ModelState.IsValid)
{
// save to db, for instance
return RedirectToAction("AnotherAction");
}
return View();
}
I have some questions regarding my MVC learning curve
Goal:
I want to get the txtMHM entered text
after the btnStat is pushed and show the entered text via a label or span or ...
The View Model you should use (simplified):
public class YourViewModel
{
public string TextEntered { get ; set ; }
}
The View:
#model YourViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.TextEntered)
<br />
<input id="btnStat" type="submit" value="MHM" />
}
#Html.LabelFor(m => m.TextEntered)
The Controller Action method:
[HttpPost]
public ActionResult ChangeLabelText(YourViewModel yourViewModel)
{
return View(yourViewModel);
}
Your Altered Code
index.cshtml
#model MVCTest1.Models.EnteredTextModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.TextEntered)
<br />
<input id="btnStat" type="submit" value="MHM" />
}
#Html.LabelFor(m => m.TextEntered)
The Model
namespace MVCTest1.Models
{
public class EnteredTextModel
{
public string TextEntered { get; set; }
}
}
The HomeController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVCTest1.Models ;
namespace MVCTest1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
[HttpPost]
public ActionResult Index(EnteredTextModel theModel)
{
return View(theModel);
}
public ActionResult About()
{
return View();
}
}
}
Sypress,
Best practice would be to use a viewmodel for your action. However, at a very simple level, based on exactly what you have above, you could use the viewbag object to pass back the input value. without further ado, the frig, i mean code :):
Controller actions:
[HttpGet]
public ActionResult ChangeLabelText()
{
return View();
}
[HttpPost]
public ActionResult ChangeLabelText(FormCollection formCollection)
{
ViewBag.LastNameEntered = formCollection["txtName"];
return View();
}
View stuff (assumes that the view is named ChangeLabelText.cshtml of course):
#{
ViewBag.Title = "ChangeLabelText";
}
<h2>ChangeLabelText</h2>
<form action="ChangeLabelText" method="post">
<input id="txtMHM" type="text" name="txtName" value="" />
<input id="btnStat" type="submit" value="Post" />
<br />
#Html.Label("Entered Text");
<span id="spnEnteredText">#ViewBag.LastNameEntered </span>
</form>
and the above is called as such http://localhost:xxxx/Home/ChangeLabelText (where xxxx is the port number of your dev server)
I would add that this would NOT be the way that I would approach this to be honest, but is my direct response to your example. go for sharks' example using the viewmodel.
good luck
[EDIT] - I've updated my answer now that I'm at a machine, so the above should work as intended.