I am new to the web side of things and I am currently struggling with Razor Pages. Can someone explain the ways I can get a value from control in this case.
How can I extract the content of the selected and pass it to a variable to the code behind;
#page
#model ViewToVM.Pages.IndexModel
#{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<section id="cityList">
<select id="selectedCity">
#using Model;
#foreach(City city in Model.Cities)
{
<option>#city.SelectedCity</option>
}
</select>
</section>
with this code behind
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using ViewToVM.Model;
namespace ViewToVM.Pages
{
public class IndexModel : PageModel
{
public List<City> Cities = new List<City>()
{
new City("Sofia"),
new City("Plovdiv"),
new City("Velingrad")
};
public string selectedCities = string.Empty;
public void OnGet()
{
}
}
}
The City class just contains a single string for demo purposes. I know this is probably a pretty bad way to do the code behind but It help me illustrate the problem better.
you can use Javascript/Jquery and add an onchange event listener that can make a Ajax call and pass it's value to the controller. similar to the code below:
<script type="text/javascript">
// assuming you're using jQuery
$("#selectedCity").change( function (event) {
$.ajax({
url: "Controller/PostDropdown/",
data: { id = $(this).val() },
type: "POST",
dataType: "html",
success: function (data, textStatus, XMLHttpRequest) {
// do something
}
});
});
You should wrap select with form. When form was submitted, it will call your controller.
see this:
Submitting form and pass data to controller method of type FileStreamResult
Related
I need some help. I am trying to pass ShowSeatsViewModel to Seats.cshtml bind it with passed view model's field and send it back with new values to controller.
ViewModel :
using System.Collections.Generic;
namespace theatre_dotNET.Models
{
public class SpectacleShowsViewModel : Spectacle
{
public List<Show> IncomingShows { get; set; }
public Show pickedShow { get; set; }
public int[] availableSeats { get; set; }
public int[] bookedSeats { get; set; }
public SpectacleShowsViewModel(Spectacle s, List<Show> incomingShows)
{
this.SpectacleId = s.SpectacleId;
this.Title = s.Title;
this.Description = s.Description;
this.Price = s.Price;
this.VideoLink = s.VideoLink;
this.Rating = s.Rating;
IncomingShows = incomingShows;
}
}
}
Two methods of controller :
[Authorize]
public IActionResult Seats(Show chosenShow)
{
int[] availableSeats = _context.Seats.Select(s => s.SeatId).ToArray();
int[] bookedSeats = _context.BookedSeats.Where(i => i.ShowId == chosenShow.ShowId).Select(s => s.SeatId).ToArray();
return View(new ShowSeatsViewModel(chosenShow, availableSeats, bookedSeats));
}
[Authorize]
[HttpPost]
public IActionResult Seats(ShowSeatsViewModel chosenShowSeatsViewModel)
{
return Content("Picked seats : "+chosenShowSeatsViewModel.PickedSeats);
}
View:
#model ShowSeatsViewModel
<h1>Chosen Spectacle : Model.SpectacleId</h1>
<form asp-controller="Booking" asp-action="Seats" method="post">
<div class="row">
#foreach(var seat in Model.AvailableSeats)
{
#if(Model.UnavailableSeats.Contains(#seat))
{
<div class="col">
#Html.CheckBoxFor(m=>m.PickedSeats[#seat-1])
#Html.LabelFor(m=>m.PickedSeats[#seat-1],#seat.ToString())
</div>
}
else
{
<div class="col">
#Html.CheckBoxFor(mdl => mdl.PickedSeats[#seat-1])
#Html.LabelFor(mdl => mdl.PickedSeats[#seat-1],#seat.ToString())
</div>
}
}
</div>
<button type="submit">Submit</button>
</form>
And an error - after choosing checkboxes and clicking submit button:
InvalidOperationException: Could not create an instance of type 'theatre_dotNET.Models.ShowSeatsViewModel'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'chosenShowSeatsViewModel' parameter a non-null default value.
How could I send existing(passed from Controller) ViewModel via post method? Is it possible?
EDIT: I'm updating my answer.
In your case, you can't model bind to that Object without custom model binding.
It's a complex object that doesn't have a parameterless constructor.
You need to have all of the properties in the form to pass the entire model with. As you stated that's not what you want.
In your case a custom model binder is a complex implementation that you would have to do over and over throughout the app. I wouldn't recommend this approach.
On the client side I would use a library like JQUERY to perform the post for complex objects.
Here is an example.
Create a JS script to run these POST requests with complex objects with the following function.
Here is an example with JQuery
function ajaxRequest(httpVerb, url, model, onSuccess, onFail, onComplete) {
if (httpVerb === null || httpVerb.length === 0) httpVerb = "POST";
$.ajax({
url: url,
type: httpVerb,
cache: false,
traditional: true,
data: JSON.stringify(model),
dataType: "json",
contentType: 'application/json; charset=utf-8'
}).done(function (data) {
//onSuccess()...
}).fail(function (err) {
//onFail()...
}).always(function (data) {
//onComplete()...
});
}
Here is how you would call it
var model = #Html.Raw(Json.Encode(Model)); //this gets your view model and converts it to a JS object.
//Or you can take the time and create it manually
var model = {...}
//take the form values and replace the model properties as needed
// make sure to give your HTML elements in the forms ID attributes so you can select them.
model.PickedSeats = $('#myCheckboxById').is(':checked');
...
// do the same with the other form values
ajaxRequest("POST", "/Booking/Seats", model , null, null, null);
//the null values being passed in are the callback functions you would perform in the method signature. I just left them null to simplify things.
Using jquery.ajax, I am trying to return a view, that has a nested partial view to display a datatable. The initial view is returning, but the datatable is not showing or rendering.
AJAX
$.ajax({
type: "GET",
url: "/Controller/Action,
data: {
custNum: custNum
},
success: function (data) {
$('#DivToRenderResults').html(data);
}
Controller
public ActionResult Action(string custNum)
{
Model ReturnModel = GetData(custNum)
if (Request.IsAjaxRequest())
{
return PartialView(ReturnModel);
}
return View(ReturnModel );
}
Model
public class Model
{
public FirstViewsModel FirstViewsModel {get;set;)
public IEnumerable<DataTableModel> DataTableModel {get;set}
}
I ultimately want to use ajax to dynamically load different tabs that all will have nested datatables in partial views, but I am unable to get this first one to work. Please help, & thank you!
Target View
<div id="DivToRenderResults">
<\div>
// Inside the div
#model Model
<div>
// FirstViewModelInfo
<div>
// This one is not rendering in the return
#Html.Partial("_DataTableView", Model)
</div>
</div>
I have some basic CRUD views for a model:
public class Task
{
public Task()
{
this.Users = new List<ApplicationUser>();
}
public string Id { get; set; }
public string Name { get; set; }
public DateTime DueDate { get; set; }
public virtual IList<ApplicationUser> Users { get; set; }
}
Now, when I edit a Task, I want to have a textbox where
you can enter the username
click search
return any results that matches the criteria
select one or more users from results // this is bound to Users property
save the task
All this done within the edit view.
Everything works fine CRUD, except I don't know how to implement the search withing the edit view.
P.S. I have a feeling I need some Ajax forms with some partial view ...
The general idea behind this solution is to request user to enter username they are searching for and then sending a request to the server for retrieving all users with that username. Once a response is received, then we dynamically populate a select with the results received from the server and make user select a username.
Note: I don't recommend you to use this solution in its current state as I always discourage mixing Javascript code with your views. I strongly recommend to move your Javascript code in a different file!
UsernameModel.cs
public class UsernameModel
{
[Required]
public string Username { get; set; }
}
UserController.cs
using Newtonsoft.Json;
public class UserController : Controller
{
...
[HttpPost]
public ActionResult Get(UsernameModel model)
{
// user service has code to search for users
// whose username equals to or is similar to model.Username
var users = userService.GetUsersByUsername(model.Username);
var response = new
{
Users = users
};
return Content(JsonConvert.Serialize(response), "application/json");
}
...
}
View:
<!-- HTML Markup to edit different task properties -->
<input type="hidden" id="UserSearchUrl" value="#Html.Action("Get", "User")" />
<label for="Username">Username:</label>
<input type="text" name="Username" id="Username" />
<button id="SearchUsername" type="button">Search</button>
<select id="UserSelect"></select>
<script type="text/javascript">
$(function () {
$('#SearchUsername').on('click', function () {
$.ajax({
type: "POST",
url: $("#UserSearchUrl").val(),
contentType: "application/json",
data: { Username: $('#Username').val() },
dataType: "json",
success: function (data, textStatus, jqXHR) {
for (var i = 0; i < data.Users.length; i++) {
var option = $('<option>').attr('val', data.Users[i]);
option.text(data.Users[i]);
$('#UserSelect').append(option);
}
},
error: function (jqXHR, textStatus, errorThrown) {
// enter error handling code here
}
});
});
});
</script>
This is just 1 possible way of searching for users. It uses Javascript DOM Manipulation and Ajax. There are several other ways of achieving this other than this one but all will involve some sort of Javascript.
Another possible way of doing this is to loading all users at the same time as loading task information on the edit page. Then search for users using Javascript within client's browser, thus removing a need for sending request to the server. I can give an example of this solution if you would like.
I am still new to MVC and working my way around it. I need to get the "name" column of my district table into a dropdownlist to be able to pick from different Districts. The end game is that the user will pick a District from the dropdownlist and then be directed to a page where a list of schools(in a different table) will be shown with the selected district (i think that would be a query on the database using the value given from the dropdownlist). Basically what I have done so far is:
Create an MVC Application.
Create a Entity Framework Model.
Create an empty controller.
Create a view model(since every tutorial/ site answer has said to do
so)
Create a view.
I replicate step by step what these tutorials are telling me to do, but I get a different result. My dropdownlist gives me this outcome:
I need help sorting out what could be going wrong and why the data is not showing up in my dropdownlist.
Try I believe you are using the wrong SelectList constructor. Assuming you want the value of the drop down list to be the "leaID" property
#Html.DropDownList("myList", new SelectList(ViewBag.districts, "leaId", "name")
I would however, approach it another way which will keep it mostly strongly typed:
public class DistrictViewModel
{
public string SelectedDistrictId { get; set; }
public IEnumerable<SelectListItem> Districts { get; set; }
}
Action:
public ActionResult Index()
{
var viewModel = new DistrictViewModel()
{
Districts = new SelectList(db.Districts.ToList(), "leaID", "name")
}
return View(viewModel);
}
cshtml:
#model DistrictViewModel
#Html.DropDownListFor(m => m.SelectedDistrictId, Model.Districts)
Here is my answer to your comment using ajax
//Model
public class DistrictViewModel
{
public string name {get;set;}
public SelectList District {get;set;}
public int SelectedDistrict {get;set}
}
//Controller
public class DistrictController : Controller
{
KUDEREntities db = new KUDEREntities();
public ActionResult Index()
{
var model = new DistrictViewModel();
model.Districts = db.Districts.ToList();
model.SelectedDistrict=0;
return view(model);
}
[HttpPost]
public ActionResult Search(int id)
{
//do the search with the id of the selected district
var data = db.Districts.Where(m=>m.leaId = id).FirstorDefault();//this would return the whole object.
return Json(data, JsonRequestBehavior.AllowGet);
}
}
//Index View
#Model DistrictViewModel
<div>
//with this your selector would be "#SelectedDistrict"
#Html.DropDownListFor(model=>model.SelectedDistrict, new SelectList(Model.Districts,"leaId","name",Model.SelectedDistrict), new {#class=""})
//with this your selector would be "#myList"
//#Html.DropDownList("myList", new SelectList(ViewBag.districts, "leaId", "name", Model.SelectedDistrict)
</div>
<script>
$(document).ready(function(){
//when you want to search for the id selected, you just need to call the Search function below
function Search() {
//... now you have the value of the selecteditem
var parameters = { id: $("#SelectedDistrict").val() };
$.ajax({
type: 'post',
url: '#Url.Action("Search", "District")',
cache: false,
contentType: "application/json; charset=utf-8",
dataType: "html",
async: true,
data: JSON.stringify(parameters),
success: function (data) {
//...do whatever with the data
},
failure: function (msg) {
//... show a message of error
}
});
}
});
</script>
I my below code i am calling partial view with ajax but when i click on the link of product Name the description of that product is not retrieved through ajax and error of ajax executes. I am retrieving the details of items selected by user on the same page but it is not retrieved. Please give any suggestion where is the issue arising because i am new to MVC. thanks...
Create.cshtml
#model List<PartialView.Models.tbl_product>
<!DOCTYPE html>
<html>
<head>
<title>Create</title>
<script src="#Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.msg').click(function () {
var id = this.id;
$.ajax({
url: "/Category/Display",
data: { data: id },
success: function (mydata) {
$("#link").empty().append(mydata);
},
error: function (mydata) { alert("error"); },
type: "POST"
});
return false;
});
});
</script>
</head>
<body>
#foreach (var item in Model)
{
<a class="msg" href="#" id="#item.ProductId">#item.ProductName</a>
}
<div id="link">
</div>
</body>
</html>
ClicksUs.cshtml (PartialView)
#model List<PartialView.Models.tbl_product>
#foreach(var items in Model)
{
#items.ProductDesc
}
CategoryController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PartialView.Models;
namespace PartialView.Controllers
{
public class CategoryController : Controller
{
dbEntities dbentity = new dbEntities();
public ActionResult Create()
{
return View(dbentity.tbl_product.ToList());
}
public ActionResult Display(int data)
{
var query = dbentity.tbl_product.First(c => c.ProductId == data);
return PartialView("ClicksUC", query);
}
}
}
Your Details controller action selects a single element here (because you are calling .First()):
public ActionResult Display(int data)
{
var query = dbentity.tbl_product.First(c => c.ProductId == data);
return PartialView("ClicksUC", query);
}
So the type of the query variable is tbl_product and not List<tbl_product>.
On the other hand your partial's model is List<PartialView.Models.tbl_product> which is obviously wrong.
Your partial's model should be a single tbl_product:
#model PartialView.Models.tbl_product
#Model.ProductDesc
Oh and what others said about the typo in your partial view name.
there are three issues in the code that you could address.
One is a typo (the partialview is called ClicksUS, NOT ClicksUC),
the other is related to the way you return the data
the third is that you use the type: "POST", you should change this to type: "GET".
try changing the code to:
public ActionResult Display(int data)
{
// using First() would have caused you an error in the view if not found
// still not perfect below, but a step closer
var query = dbentity.tbl_product.FirstOrDefault(c => c.ProductId == data);
// You had ClicksUC, rather than ClicksUS
return PartialView("ClicksUS", query);
}
I'd also strongly suggest that you create a ViewModel for your data, rather than passing the objects from the database as this will allow you to control exactly the data that should be viewed and how it should be formatted etc.
[edit]
Also, as Darin says, based on a single row being retruned, you should change your partial view model type to:
#model PartialView.Models.tbl_product