Razor MVC doubts in a small sample program - c#

I just started studying MVC few days back. As far as I know, I did a small sample program. But some doubts I been facing. I am posting my doubts and code below. Please help me to understand it clearly.
Here I created four views and controller and a student class.
StudentClass
public class Student
{
public string Name { get; set; }
public string Age { get; set; }
public string Place { get; set; }
}
ViewOne
#model MyTestMVCApp.Models.Student
#{
ViewBag.Title = "ViewOne";
}
#using (Html.BeginForm())
{
<table style="border-color:Black;">
<tr>
<td>Name</td><td>Age</td><td>Place</td>
</tr>
<tr>
<td>--</td><td>--</td><td>--</td>
</tr>
</table>
<label>Enter Name : </label>
#Html.TextBoxFor(model => model.Name, new { name = "name"});
<input name="submit" type="submit" id="btnStart" class="button" value="Start Filling Details" />
ViewTwo.cshtml
#model MyTestMVCApp.Models.Student
#{
ViewBag.Title = "ViewTwo";
}
#using (Html.BeginForm())
{
<table style="border-color:Black;">
<tr>
<td>Name</td><td>Age</td><td>Place</td></tr>
<tr>
<td>#Model.Name</td><td>#Model.Age</td><td>#Model.Place</td>
</tr>
</table>
<label>Enter Age : </label>
#Html.TextBoxFor(model => model.Age, new { name = "age" });
<input name="submit" type="submit" id="btnNext" class="button" value="Next" />
}
ViewThree.cshtml
#model MyTestMVCApp.Models.Student
#{
ViewBag.Title = "ViewThree";
}
#using (Html.BeginForm())
{
<table style="border-color:Black;">
<tr><td>Name</td><td>Age</td><td>Place</td></tr>
<tr><td>#Model.Name</td><td>#Model.Age</td><td>#Model.Place</td></tr>
</table>
<label>Enter Age : </label>
#Html.TextBoxFor(model => model.Place, new { name = "place" });
<input name="submit" type="submit" id="btnNext" class="button" value="Next" />
}
ViewFour.cshtml
#model MyTestMVCApp.Models.Student
#{
ViewBag.Title = "ViewFour";
}
#{
<table style="border-color:Black;">
<tr><td>Name</td><td>Age</td><td>Place</td></tr>
<tr><td>#Model.Name</td><td>#Model.Age</td><td>#Model.Place</td></tr>
</table>
}
MyViewController.cs
public class MyViewController : Controller
{
public ActionResult ViewOne()
{
Student student = new Student();
return View(student);
}
[HttpPost]
public ActionResult ViewOne(Student student)
{
return View("ViewTwo", student);
//return RedirectToAction("ViewTwo",student);
}
[HttpPost]
public ActionResult ViewTwo(Student student)
{
return View("ViewThree", student);
//return RedirectToAction("ViewThree", student);
}
[HttpPost]
public ActionResult ViewThree(Student student)
{
return View("ViewFour", student);
}
}
My doubts
doubt 1. On the button click in ViewTwo,
[HttpPost]
public ActionResult ViewOne(Student student)
{
}
is debugging instead of ViewTwo's [HttpPost] actionresult.. Why ?
doubt 2. How can I pass the same instance of the student object I created in the ViewOne to all other Views , because my need is
On ViewOne, I get 'name' property of the student, then I pass the same object to ViewTwo.
On ViewTwo, I get 'age' property of the student, then I pass the same object to ViewThree.
On ViewThree, I get 'place' property of the student, then I pass the same object to ViewFour.
On ViewFour I display all the values of the student that I get through the above views.

It looks like you are returning ViewTwo from ViewOne's post action. When you do that you're still routing to the ViewOne action. The code below will show in your address bar as ViewOne, even though you're returning ViewTwo. Looks like you had the right idea at some point where you had a RedirectToAction call but you don't have an HttpGet for the ViewTwo action.
[HttpPost]
public ActionResult ViewOne(Student student)
{
return View("ViewTwo", student);
//return RedirectToAction("ViewTwo",student);
}
Another option, and this would probably be useful for you since you're trying to pass your Student object, would be to use RedirectToRoute where you pass the Student name, id or some other identifying item, as a parameter in the route. So the uri would end up looking something like this: ../MyView/ViewTwo/Joe

Because you are calling from ViewOne. if you want execute ViewTwo Action then use as below
#using (Html.BeginForm("ViewTwo", "MyView", FormMethod.Post))

It looks like it is the view definition that you have missed a small bit of logic.
the reason why you are hitting ViewOne on postback is because you are not setting the values the form it posting back to.
so in your ViewOne.cshtml and subsequent views you would need
#Html.BeginForm("ViewTwo","MyViewController")
{
//View code
}
The HTML.BeginForm will render with the RouteData if you do not provide it in the call for begin form.

Related

How do I set the default value to a hidden input box using ASP.NET MVC?

How can do I set the default value to a hidden input box in html page using ASP.NET MVC.
Seems you are trying to set hidden value on asp.net MVC. You could
try below way.
Model:
public class HiddenValueModel
{
public int HiddenValueId { get; set; }
public String HiddenValueName{ get; set; }
}
Load Default View From Controller:
public IActionResult HiddenValueExample()
{
return View();
}
View:
#model MVCApps.Models.HiddenValueModel
#{ ViewBag.Title = " "; }
<h2>Hidden Value Example </h2>
<hr />
#using (Html.BeginForm("HiddenValueExamplePost", "controllerName"))
{
<table class="table table-sm table-bordered table-striped">
<tr><th>HiddenValueName </th><td id="HiddenValueName"> #Html.TextBoxFor(r => Model.HiddenValueName, new { #class = "form-control" })</td></tr>
<tr><th>HiddenValue Id Which Is Hidden</th><td id="HiddenValueId"><input type="hidden" id="HiddenValueId" name="HiddenValueId" value="01052022" /></tr>
</table>
<input id="Button" type="submit" value="Save" class="btn btn-primary" style="margin-left:1091px" />
}
Note: Here you could see HiddenValueId we have set the value into the feild and keep that hidden. But when you would submitted the
value to the controller it would be there. Additionally, if you want to bind the hidden value from your backend you can use this way #Html.HiddenFor(m => m.HiddenValueId, new { #value = Model.HiddenValueId} ). You could also have a
look more details on official document here
Submit Value To Controller:
[HttpPost]
public IActionResult HiddenValueExamplePost(HiddenValueModel modelWithHiddenValue)
{
return View();
}
Output:
When Bind From Controller:
public IActionResult HiddenValueExample()
{
var hiddenExamVal = new HiddenValueModel();
hiddenExamVal.HiddenValueId = 10101;
hiddenExamVal.HiddenValueName = "Test Hidden Value";
return View(hiddenExamVal);
}
Bind From Controller and submit that value again to controller:
In this case update the view like this :
#model MVCApps.Models.HiddenValueModel
#{ ViewBag.Title = " "; }
<h2>Hidden Value Example </h2>
<hr />
#using (Html.BeginForm("HiddenValueExamplePost", "StackOverFlow"))
{
<table class="table table-sm table-bordered table-striped">
<tr><th>HiddenValueName </th><td id="HiddenValueName"> #Html.TextBoxFor(r => Model.HiddenValueName, new { #class = "form-control" })</td></tr>
<tr><th>HiddenValue Id Which Is Hidden</th><td id="HiddenValueId">#Html.HiddenFor(m => m.HiddenValueId, new { #value = Model.HiddenValueId} )<br /></tr>
</table>
<input id="Button" type="submit" value="Save" class="btn btn-primary" style="margin-left:1091px" />
}
<br />
Output Using Backend Binding:
Hope it would guided you accordingly.
Creating a Hidden Field in ASP .NET MVC
Studentmodel:
public class Student{
public int StudentId { get; set; }
public string StudentName { get; set; }}
HiddenFor() in Razor View:
#model Student
#Html.HiddenFor(m => m.StudentId)
Html Result :
<input data-val="true"
data-val-number="The field StudentId must be a number."
data-val-required="The StudentId field is required."
id="StudentId"
name="StudentId"
type="hidden"
value="" />
Html.Hidden() :
#model Student
#Html.Hidden("StudentId")
Html Result :
<input id="StudentId" name="StudentId" type="hidden" value="1" />
Basic Helper (#Html.Hidden())
If you want a Hidden Field with its value set you can try this:
#Html.Hidden("Jeremy", "Thompson")
The Hidden Field's name will be "Jeremy", and the value of the Hidden Field will be "Thompson".
Strongly Typed Helper (#Html.HiddenFor()) / Model Binding
The strongly typed helper contains 2 parameters:
Hidden Field name which is the name of a Model Property.
Value of Hidden Field (if we want to set the value from the view).
Declaration of Hidden Field using strongly typed helper:
#Html.HiddenFor(m => m.StudentID, new { Value = "1" })
Ref

415 Status When Passing Model into Controller Action in ASP.NET Core 3.1 MVC

I've seen many tutorials and documentation pass the model as an argument in an Action in a controller. Every time I do this I get a 415 status error (incorrect media type) when the action is called. This is problematic for me because my fields clear after the action occurs. Many have suggested calling the model when I return the View, but that has not been working for me. Does anyone know why that is and how I can fix it? I'm so frustrated I've tried so many things and it just never works :(
Example of how I want to pass the model as an argument:
[HttpGet("[action]")]
public async Task<IActionResult> Search(Movies model, int ID, string titleSearch,
string genreSearch)
{
return View(model);
}
My View:
#model IEnumerable<MyApp.Models.Movies>
#{
ViewData["Title"] = "Movies";
}
<form method="get" role="form" asp-controller="MoviesList" asp-action="Index">
<label>Movie Genre</label>
<select name="movieGenre" asp-items="#(new SelectList(ViewBag.genre, "ID", "Genre"))"></select>
<label>Movie Title</label>
<input type="search" value="#ViewData["movieTitle"]" name="movieTitle" />
<input type="submit" value="Search" asp-controller="MoviesList" asp-action="Search" />
</form>
<input type="hidden" name="ID" value="#ViewBag.pageID"
<table>
<thead>
<tr>
<th>
#Html.DisplayNameFor(m => m.Title)
</th>
<th>
#Html.DisplayNameFor(m => m.Genre)
</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model)
{
<tr>
<th>
#Html.DisplayFor(modelItem => item.Title)
</th>
<th>
#Html.DisplayFor(modelItem => item.Genre)
</th>
</tr>
}
</tbody>
</table>
My Controller:
//This action is called when the page is first called
[HttpGet("[action]")]
[Route("/MoviesList/Index/id")]
public async Task<IActionResult> Index(int id)
{
//using ViewBag to set the incoming ID and save it in the View
//so that I can access it from my search action
ViewBag.pageID = id;
//calling a query to load data into the table in the View
//var query = query
return View(await query);
}
//searching the movies list with this action
[HttpGet("[action]")]
public async Task<IActionResult> Search(int ID, string titleSearch, string genreSearch)
{
int id = ID;
ViewData["titleSearch"] = titleSearch;
//do some necessary conversions to the incoming data (the dropdowns for example come in as
//integers that match their value in the DB
var query = from x in _db.Movies
.Where(x => x.Id == id)
select x;
//some conditionals that check for null values
//run the search query
query = query.Where(x =>
x.Title.Contains(titleSearch) &&
x.Genre.Contains(genreSearch));
//when this return happens, I do get all of my results from the search,
//but then all of the fields reset & my hidden ID also resets
//this is problematic if the user decides they want to search again with
//different entries
return View("Index", await query.AsNoTracking().ToListAsync());
}
Overall, my goal is to not have any of the fields clear after my action is complete, and allow the user to re-call the action with new entries. From my understanding, passing the model as an argument can help me achieve my goal, but I haven't had any luck. Please let me know how I can achieve this goal. Thank you for your time!
There are so many things wrong in your code. I am not sure where to start but will try my best to list out a few:
Use of [HttpGet]
Use of Attribute Routing, [Route]
Form post
Overuse of ViewBag
1. Use of [HttpGet]
I don't want to say the way you used [HttpGet] passing a name as the parameter is wrong, but your setup will always ignore the controller name!
The [action] you passed in is call token replacement, which will be replaced with the value of the action name so:
/*
* [HttpGet("[action]")] on Search action => [HttpGet("search")] => matches /search
* [HttpGet("[action]")] on Index action => [HttpGet("index")] => matches /index
*/
See how wrong that is! You're missing the controller name!
A request /moviesList/index will not call the Index method from the MoviesList controller, but a request /index will!
Just take out the template/token replacement parameter. And by default, if you don't mark the controller action with any HTTP verb templates, i.e., [HttpGet], they're default to handle HTTP GET requests.
2. Use of Attribute Routing, [Route]
I don't want to say using attribute routing in a Model-View-Controller application is wrong, but attribute routing is used mostly when you're building a RESTful API application.
By default, the app is setup to use the conventional routing, which should come with the template when you first create your application:
namespace DL.SO.SearchForm.WebUI
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
The way you used [Route] attribute gives me an impression that you don't know what they're or at least you are confused. With the conventional routing, even if you don't put [Route] on the controllers, the following requests should arrive to their corresponding controller actions by the "default" routing:
/*
* /moviesList/index GET => MoviesList controller, Index action
* /moviesList/search GET => MoviesList controller, Search action
*/
By the way, a controller named MoviesListController is awful. I will just call it MovieController.
3. Form Post
Within the form, you can't specify a controller and the action on the submit button. It's not an anchor tag anyway.
And <input type="hidden" name="ID" value="#ViewBag.pageID" is outside the form. How would the form know what that is and post the correct value back?
4. Overuse of ViewBag / ViewData
Technically you can only use ViewBag to transfer data between controller to view. ViewData is only valid in the current request, and you can only transfer data from controller to view, not vice-versa.
In additional, they're so-called weakly typed collections. They're designed to transfer small amount of data in and out of controllers and views, like the page title. If you overuse them, your applications will become so hard to maintain as you have to remember what type the data is when using it.
By overusing ViewBag / ViewData, you're basically removing one of the best features about C# & Razor - strongly typed.
The best approach is to specify a view model in the view. You pass an instance of the view model to the view from the controller action. The view model defines only the data the view needs! You should not pass your entire database model to the view so that users can use your other important information!
My approach
Instead of using a single method to handle listing all the movies as well as the search filters, I would like to separate them. The search form will be using [HttpPost] instead of [HttpGet].
That way I will only need to post back the search filters data, and I can now define custom parameters on the Index action and have the Post action redirect to the Index action.
I will show you what I mean.
View Models
First I will define all the view models I need for the view:
namespace DL.SO.SearchForm.WebUI.Models.Movie
{
// This view model represents each summarized movie in the list.
public class MovieSummaryViewModel
{
public int MovieId { get; set; }
public string MovieTitle { get; set; }
public string MovieGenre { get; set; }
public int MovieGenreId { get; set; }
}
// This view model represents the data the search form needs
public class MovieListSearchViewModel
{
[Display(Name = "Search Title")]
public string TitleSearchQuery { get; set; }
[Display(Name = "Search Genre")]
public int? GenreSearchId { get; set; }
public IDictionary<int, string> AvailableGenres { get; set; }
}
// This view model represents all the data the Index view needs
public class MovieListViewModel
{
public MovieListSearchViewModel Search { get; set; }
public IEnumerable<MovieSummaryViewModel> Movies { get; set; }
}
}
The Controller
Next, here comes the controller:
One thing to pay attention here is that you have to name the POST action parameter the same way as you define it in the view model, like so MovieListSearchViewModel search.
You can't name the parameter name something else because we're posting partial view model back to MVC, and by default, the model binding will only bind the data for you if it matches the name.
namespace DL.SO.SearchForm.WebUI.Controllers
{
public class MovieController : Controller
{
// See here I can define custom parameter names like t for title search query,
// g for searched genre Id, etc
public IActionResult Index(string t = null, int? g = null)
{
var vm = new MovieListViewModel
{
Search = new MovieListSearchViewModel
{
// You're passing whatever from the query parameters
// back to this search view model so that the search form would
// reflect what the user searched!
TitleSearchQuery = t,
GenreSearchId = g,
// You fetch the available genres from your data sources, although
// I'm faking it here.
// You can use AJAX to further reduce the performance hit here
// since you're getting the genre list every single time.
AvailableGenres = GetAvailableGenres()
},
// You fetch the movie list from your data sources, although I'm faking
// it here.
Movies = GetMovies()
};
// Filters
if (!string.IsNullOrEmpty(t))
{
// Filter by movie title
vm.Movies = vm.Movies
.Where(x => x.MovieTitle.Contains(t, StringComparison.OrdinalIgnoreCase));
}
if (g.HasValue)
{
// Filter by movie genre Id
vm.Movies = vm.Movies
.Where(x => x.MovieGenreId == g.Value);
}
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
// You have to name the paramter "Search" as you named so in its parent
// view model MovieListViewModel
public IActionResult Search(MovieListSearchViewModel search)
{
// This is the Post method from the form.
// See how I just put the search data from the form to the Index method.
return RedirectToAction(nameof(Index),
new { t = search.TitleSearchQuery, g = search.GenreSearchId });
}
#region Methods to get fake data
private IEnumerable<MovieSummaryViewModel> GetMovies()
{
return new List<MovieSummaryViewModel>
{
new MovieSummaryViewModel
{
MovieId = 1,
MovieGenreId = 1,
MovieGenre = "Action",
MovieTitle = "Hero"
},
new MovieSummaryViewModel
{
MovieId = 2,
MovieGenreId = 2,
MovieGenre = "Adventure",
MovieTitle = "Raiders of the Lost Ark (1981)"
},
new MovieSummaryViewModel
{
MovieId = 3,
MovieGenreId = 4,
MovieGenre = "Crime",
MovieTitle = "Heat (1995)"
},
new MovieSummaryViewModel
{
MovieId = 4,
MovieGenreId = 4,
MovieGenre = "Crime",
MovieTitle = "The Score (2001)"
}
};
}
private IDictionary<int, string> GetAvailableGenres()
{
return new Dictionary<int, string>
{
{ 1, "Action" },
{ 2, "Adventure" },
{ 3, "Comedy" },
{ 4, "Crime" },
{ 5, "Drama" },
{ 6, "Fantasy" },
{ 7, "Historical" },
{ 8, "Fiction" }
};
}
#endregion
}
}
The View
Finally here comes the view:
#model DL.SO.SearchForm.WebUI.Models.Movie.MovieListViewModel
#{
ViewData["Title"] = "Movie List";
var genreDropdownItems = new SelectList(Model.Search.AvailableGenres, "Key", "Value");
}
<h2>Movie List</h2>
<p class="text-muted">Manage all your movies</p>
<div class="row">
<div class="col-md-4">
<div class="card">
<div class="card-body">
<form method="post" asp-area="" asp-controller="movie" asp-action="search">
<div class="form-group">
<label asp-for="Search.GenreSearchId"></label>
<select asp-for="Search.GenreSearchId"
asp-items="#genreDropdownItems"
class="form-control">
<option value="">- select -</option>
</select>
</div>
<div class="form-group">
<label asp-for="Search.TitleSearchQuery"></label>
<input asp-for="Search.TitleSearchQuery" class="form-control" />
</div>
<button type="submit" class="btn btn-success">Search</button>
</form>
</div>
</div>
</div>
<div class="col-md-8">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Genre</th>
</tr>
</thead>
<tbody>
#if (Model.Movies.Any())
{
foreach (var movie in Model.Movies)
{
<tr>
<td>#movie.MovieId</td>
<td>#movie.MovieTitle</td>
<td>#movie.MovieGenre</td>
</tr>
}
}
else
{
<tr>
<td colspan="3">No movie matched the searching citiria!</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
Screenshots
When you first land on the Movies page:
The available Genre list as well as the movie list is shown correctly:
Search by Genre:
Search by Title:
You don't really "pass arguments" to a controller action - you're issuing HTTP requests to an endpoint defined by your application, which the various middleware running in your app attempt to process. In this case, one of those middlewares is the MVC framework/module, which tries to map route values (controller, action, etc.) to the matching classes, and query string or form values where relevant.
Since you've defined that Search action as only matching GET requests, you're reading from the query string (the ?foo=bar&bar=baz content you typically see in your navigation bar). A C# class is not something you can send as a query string value (there are ways around this, using attributes, but that's kind of overkill for your example). I'd read https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1 if you haven't already.
The Search action in your last example will work, but you've rendered the input outside the <form> element; for it to be included, you either need to render it inside the form or use the form="form id here" attribute to associate it with that form (you'll need to add an id="something" attribute to the form for that to work, as well).
<form method="get" role="form" asp-controller="MoviesList" asp-action="Index">
<label>Movie Genre</label>
<select name="movieGenre" asp-items="#(new SelectList(ViewBag.genre, "ID", "Genre"))"></select>
<label>Movie Title</label>
<input type="search" value="#ViewData["movieTitle"]" name="movieTitle" />
<input type="submit" value="Search" asp-controller="MoviesList" asp-action="Search" />
<input type="hidden" name="ID" value="#ViewBag.pageID" />
</form>
You have two choices (well, more actually, but let's say two for now) if you want to retain the values used to submit your search form:
Add the querystring values to ViewBag/ViewData (you started to do this)
Use an actual view model, rather than a collection of values
I'd personally go with #2, since it also makes your view cleaner to bind. So:
public class SearchViewModel
{
public SearchViewModel()
{
Matches = Array.Empty<Movies>();
Genres = Array.Empty<Genre>();
}
public int? ID { get; set; }
public string Title { get; set; }
public string Genre { get; set; }
public IEnumerable<Movies> Matches { get; set; }
public IEnumerable<Genre> Genres { get; set; }
}
View:
#model SearchViewModel
#{
ViewData["Title"] = "Movies";
}
<form method="get" role="form" asp-controller="MoviesList" asp-action="Index">
<label>Movie Genre</label>
<select asp-for="Genre" asp-items="#(new SelectList(Model.Genres, "ID", "Genre"))"></select>
<label>Movie Title</label>
<input type="search" asp-for="Title" />
<button>Search</button>
<input type="hidden" asp-for="ID" />
</form>
<table>
<thead>
<tr>
<th>
Title
</th>
<th>
Genre
</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model.Matches)
{
<tr>
<td>
#item.Title
</td>
<td>
#item.Genre
</td>
</tr>
}
</tbody>
</table>
Controller
If you make your action parameters nullable, you actually only need one action for both the "default" action and search:
[HttpGet("[action]")]
[Route("/MoviesList/Index/id")]
public async Task<IActionResult> Index(int? id, string title = null, string genre = null)
{
var model = new SearchViewModel();
// ... add code for populating model.Genres...
var query = _db.Movies.AsQueryable();
if(id != null)
{
model.ID = id.value;
query = query.Where(m => m.ID == id);
}
if(title != null)
{
model.Title = title;
query = query.Where(m => m.Title.Contains(title));
}
if(genre != null)
{
model.Genre = genre;
query = query.Where(m => m.Genre.Contains(Genre));
}
model.Matches = await query
.OrderBy(m => m.Title)
.ToListAsync();
return View(model);
}
This is completely untested, so caveat emptor.

How to post values using DisplayFor [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 4 years ago.
I can't get the values in controller from the post method used on the view and I don't know why. I saw a lot of forums and I thought that I was doing the right thing, but it doesn't seem to be the correct way to do because I can't get the values.
First I was using just the DisplayFor but that just shows and not pass the values then I join the HiddenFor to use that like an input like I saw in other forums. But the model always returns zero values.
AtribuiĆ§Ć£oController:
public IActionResult Create(List<Main> main)
{
return RedirectToAction(nameof(Index));
}
Index.cshtml:
#model ModelsLibrary.Main
<form asp-action="Create">
<table class="table">
<thead>
<tr>
<th>
<label>Disciplina</label>
</th>
<th>
<label>Turno</label>
</th>
<th>
<label>Tipologia</label>
</th>
<th>
<label>Docente</label>
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Turno)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.MetaDisciplina.Nome)
#Html.HiddenFor(modelItem => item.MetaDisciplina.Nome)
</td>
<td>
#Html.DisplayFor(modelItem => item.LetraTurno)
#Html.HiddenFor(modelItem => item.LetraTurno)
</td>
<td>
#Html.DisplayFor(modelItem => item.Tipologia.Tipo)
#Html.HiddenFor(modelItem => item.Tipologia.Tipo)
</td>
<td>
<select asp-for="Docente" asp-items="ViewBag.Docente"></select>
</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
Index Method
[HttpGet]
public IActionResult Index()
{
var Turno = new List<Turno>();
Main main = new Main();
main.Turno = Turno;
ViewData["Ano"] = new SelectList(_context.AnoLetivo, "Ano", "Ano");
return View(main);
}
Hi have a problem binding the values to the controller. The method create should get values in the attributes but i don't know why and heaven don't know why the values not pass... I not pass a list to the view but i want one list in the create method.... If someone can help.
Your problem is in your Controller. Your create method do redirect to your Index method but you don't pass your List main
I think your code should be like this:
[HttpGet]
public ActionResult Index()
{
List<Main> main = (List<Main>)TempData["yourData"];
if (main == null)
{
main = new List<Main>();
}
return View("Index", main);
}
public IActionResult Create(List<Main> main)
{
TempData["yourData"] = main;
return RedirectToAction(nameof(Index));
}
The way your want to redirect your data is called the POST-REDIRECT-GET pattern. If your want more information about it, visit this website : https://andrewlock.net/post-redirect-get-using-tempdata-in-asp-net-core/
--------------------EDIT--------------------
You have a binding problem while passing data from View to Controller. You can use an TempData in your View to pass your complete Model to your controller:
#model List<WebApplication1.Models.TestObject>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#foreach (var item in Model)
{
#Html.DisplayFor(m => item.ToDisplay)
}
<form action="/Home/Create" method="post">
<button type="submit">Submit</button>
</form>
<script>
$('form').submit(function() {
#{ TempData["FullModel"] = Model; }
});
</script>
In this exemple, i use a jquery script to create a TempData and send it to the controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
List<TestObject> main = (List<TestObject>)TempData["yourData"];
if (main == null)
{
main = new List<TestObject>();
main.Add(new TestObject("1"));
main.Add(new TestObject("2"));
main.Add(new TestObject("3"));
main.Add(new TestObject("4"));
main.Add(new TestObject("5"));
}
return View("Index", main);
}
[HttpPost]
public ActionResult Create()
{
List<TestObject> main = (List<TestObject>)TempData["FullModel"];
TempData["yourData"] = main;
return RedirectToAction(nameof(Index));
}
}
Hope it was helpfull

How to share data between controller and views without using ViewBag in MVC

I have created a mobile store project. There is a dropdown in my view, I need to fill this dropdown from database so I have declared a public variable in controller but it's not accessible in views. I have also tried to declare that in model class, it's working fine, but problem is that when I update the entity model from database these variable got deleted. So please suggest me how to do that and also I don't want to use ViewBag. Code which I have tried.
public SelectList Vendor { get; set; }
public ActionResult ShowAllMobileDetails(tbInsertMobile IM)
{
Vendor = new SelectList(db.Usp_VendorList(), "VendorId", "VendorName");
return View(IM);
}
Views..
#model MobileApplicationEntityFramework.Models.tbInsertMobile
#{
ViewBag.Title = "ShowAllMobileDetails";
}
#using (#Html.BeginForm())
{
<h2>ShowAllMobileDetails</h2>
<p>
#Html.ActionLink("Create New Mobile", "InsertMobile");
</p>
<fieldset>
<legend>Search Panel</legend>
<table>
<tr>
<td>Mobile Name</td>
<td>#Html.TextBoxFor(a => a.MobileName) </td>
</tr>
<tr>
<td>Mobile Manufacured</td>
<td>#Html.DropDownList("ddlVendor", Vendor, "Select Manufacurer")</td>
</tr>
</table>
</fieldset>
}
hi: you can define a static property to share to all place in your project:
public static class Global
{
public static SelectList Vendor()
{
return (new SelectList(db.Usp_VendorList(), "VendorId", "VendorName"));
}
}
and use in your views like this:
Mobile Manufacured
#Html.DropDownList("ddlVendor", namespaceOfGlobal.Vendor, "Select Manufacurer")

How to pass values by POST in ASP.NET MVC 4

I have problem with passing values by POST in ASP.NET MVC 4
This is my action in User controller:
[HttpPost]
public string Show(int? uid, string uname)
{
return uname + uid.ToString();
}
And this is how I tried to pass values in view:
#using (Html.BeginForm("Show", "User"))
{
Html.Hidden("uid", Model.Id);
Html.Hidden("uname", Model.UserName);
<input type="submit" value="+"/>
}
html:
<form action="/User/Show" method="post"> <input type="submit" value="+"/> </form>
and:
#using(Html.BeginForm("Show", "User", FormMethod.Post, new { uid = 1, uname = "user1" }))
{
<input type="submit" value="+"/>
}
html:
<form action="/User/Show" method="post" uid="1" uname="user1"> <input type="submit" value="+"/></form>
In both ways Show action receives null instead real values.
Your HtmlHelpers are not being rendered. Use Razor syntax.
#using (Html.BeginForm("Show", "User"))
{
#Html.Hidden("uid", Model.Id);
#Html.Hidden("uname", Model.UserName);
<input type="submit" value="+"/>
}
Explanation:
Calling Html.Hidden (or Html.[anything]) is a method and usually returns an IHtmlString. Without using # infront, the engine doesn't know that you're trying to output the returned string. It just thinks you're calling a method.
This is not a good approach for an action that receives data. This approach can offer many security breaches, like data injection., essentially lots of fields.
The right thing is create a Model (or a ViewModel, if you don't want to persist the data) to make the correct guidance between View and Controller:
ViewModel:
public class MyViewModel {
public int? uid { get; set; }
public string uname { get; set; }
}
View:
#model MyProject.ViewModels.MyViewModel
#using (Html.BeginForm("Show", "User"))
{
Html.HiddenFor(model => model.uid);
Html.HiddenFor(model => model.uname);
<input type="submit" value="+"/>
}
Controller:
public ActionResult Show(int modelId) {
var model = context.Model.SingleOrDefault(m => m.ModelId == modelId);
var viewModel = new MyViewModel();
viewModel.uid = model.Id;
viewModel.uname = model.UserName;
return View(viewModel);
}
[HttpPost]
public string Show(MyViewModel viewModel)
{
return viewMode.uname + viewModel.uid.ToString();
}
You're not actually creating hidden fields in your form. You need the # in front of you Hidden helper, and drop the semi-colon at the end.
#using (Html.BeginForm("Show", "User"))
{
#Html.Hidden("uid", Model.Id)
#Html.Hidden("uname", Model.UserName)
<input type="submit" value="+"/>
}
The reason your hard-coded test didn't work is that your HTML wasn't correct. You can't just put the values you want to post on the <form> element, you need to have them as hidden fields in the form.
<form action="/User/Show" method="post">
<input type="hidden" name="uid" value="1" />
<input type="hidden" name="uname" value="user1">
<input type="submit" value="+"/>
</form>
It would be better if you could use a view model.
public class MyViewModel
{
public int? Id {get;set;}
public string UserName {get;set;}
}
public ActionResult Show()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Show(MyViewModel model)
{
return Content(string.format("{0} - {1}", model.Id, model.UserName));
}
(Coded in notepad so untested, but should work.)

Categories