How can i add something to the list and display it in table in ASP .NET CORE MVC? I'm trying to do simple URL shortener, but I can't even pass full link to the view.
My model:
public class Link
{
public string FullLink { get; set; }
public string ShortenedLink { get; set; }
public static List<Link> _list = new List<Link>();
}
My controller:
public class LinkController : Controller
{
public IActionResult Index()
{
return View(Link._list);
}
[HttpPost]
public IActionResult Add(string link)
{
Link._list.Add(new Link { FullLink = link });
return RedirectToAction("Index");
}
}
My view:
#model List<UrlShortener.Models.Link>
<html>
<head>
<title></title>
</head>
<body>
#using (Html.BeginForm("Add", "Link", FormMethod.Post))
{
#Html.TextBox("myTextBox");
<input type="submit" value="Add" />
}
<div>
<table>
#foreach (var item in Model)
{
<tr><td>#item.FullLink</td></tr>
}
</table>
</div>
</body>
</html>
Can someone explain me what am I doing wrong that after clicking "Add" button nothing happens?
You need to tell your form what your textbox represents.
Instead of using "myTextBox" for the name parameter of your textbox, give it the name (link in your example) of the parameter in your controller method, public IActionResult Add(string link), you are binding your form to.
In short, you need to change the textbox declaration in your view to this:
#Html.TextBox("link")
Note: the semicolon after the Html.TextBox(...) tag is unnecessary
Related
How do you handle routing in razor pages with a search string like this:
https://localhost:5000/link?searchParam1=daniel&searchParam2=olu&Keyword=keyword.
In Razor pages, you can adding the routing you want in at the top of the razor.chshtml file like so:
#page "/preferedroute"
#model Index
#{
}
How do I do this with the search string above. It has multiple parameters. How do I translate that to the preferred route so that other pages can access it. I have a form that submits to the page.
<form class="form-inline" id="form" action="preferedroute">
<input id="searchParam1 value="dan">
<input id="searchParam2 value="olu">
<input id="keyword value="keyword">
</form>
When I submit this form to page, it submits like so:
https://localhost:5000/link?searchParam1=daniel&searchParam2=olu&Keyword=keyword
but I need it to submit like so:
https://localhost:5000/link/searchParam1/daniel/searchParam2/olu/Keyword=keyword
Now the problem is that I have this form in the shared _layout.cshtml file. So I cannot use tag helpers(asp-for) in the form like so because it does not have a page model:
<form class="form-inline" id="form" action="preferedroute">
<input asp-for="searchParam1" value="dan" >
<input asp-for="searchParam2 value="olu">
<input asp-for="keyword value="keyword">
</form>
How do I accomplish the required result when the form cannot use tag helpers?
How do you handle routing in razor pages with a search string like this: https://localhost:5000/link?searchParam1=daniel&searchParam2=olu&Keyword=keyword
You can refer to the following code snippet to bind and handle search terms.
public class LinkModel : PageModel
{
[BindProperty(SupportsGet = true)]
public SearchTerms searchTerms { get; set; }
public void OnGet()
{
var searchParams = searchTerms;
//...
//code logic here
//...
}
}
Class SearchTerms
public class SearchTerms
{
public string searchParam1 { get; set; }
public string searchParam2 { get; set; }
public string keyword { get; set; }
}
Test Result
I expected to see something like return Page(model: MyModel); in ASP Razor Pages. instead the Page(); has no parameter.
So I can return Pages which does not have PageModel class.
I cant use TempData as MyModel is a complex type.
How do I get the same functionality we have with ASP MVC return View(model: MyModel);
Please, The question is not for all MVC developers but experienced ASP.Net Core Razor Page developers.
Thank you.
Ok here is an example from a simple Restaurant app.
As you can see the Restaurant object is a property inside the DetailModel. Once i set it inside the OnGet() method. I am able to access its data inside my Razor Page View.
public class DetailModel : PageModel
{
private readonly IRestaurantData restaurantData;
[TempData]
public string Message { get; set; }
public Restaurant Restaurant { get; set; }
public DetailModel(IRestaurantData restaurantData)
{
this.restaurantData = restaurantData;
}
public IActionResult OnGet(int restaurantId)
{
Restaurant = restaurantData.GetById(restaurantId);
if(Restaurant == null)
{
return RedirectToPage("./NotFound");
}
return Page();
}
}
and the view from the page.
#page "{restaurantId:int}"
#model MyProject.Pages.Restaurants.DetailModel
#{
ViewData["Title"] = "Detail";
}
<h2>#Model.Restaurant.Name</h2>
<div>
Id: #Model.Restaurant.Id
</div>
<div>
Location: #Model.Restaurant.Location
</div>
<div>
Cuisine: #Model.Restaurant.Cuisine
</div>
#if(Model.Message != null)
{
<div class="alert alert-info">#Model.Message</div>
}
<a asp-page="./List" class="btn btn-default">All Restaurants</a>
Really Razor pages work as one so you do not have to return the Model. You just bind it and you have access inside the page.
Does this makes sense?
Please also read the DOCS for more information: https://learn.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio
Is it possible to pass another controller's view to the first controller's view? I have controller1 with view1. I need to call another controller2 action method from view1 and pass the view2 to a div in view 1.
I tried #html.Action("action","controller"). This called controller 2, but was not passing the view2 to view1.
Am I doing it wrong? How can I do that?
This example is something you can use. I did not put it into an ASP.NET Fiddle because we are dealing with TWO view.
Controller/ViewModel of First
namespace Testy20161006.Controllers
{
//I'm showing how to pass data from one Controller Action to another Controller Action.
//With the data you can render your second view however you like with the data.
//We pass data NOT views. You could use a partial view, but I am showing the most basic way.
public class NewbieDevViewModel
{
public String DataToPassToNewControllerAction { get; set; }
}
public class HomeController : Controller
{
//I am using Tut145 for my first Controller/Action/View, but you could have called it Index
[HttpPost]
public ActionResult Tut145(NewbieDevViewModel passedData)
{
//passing simple string, so I can pass it using my QueryString
return RedirectToAction("MyAction2", "Home2", new { passedData = passedData.DataToPassToNewControllerAction });
}
public ActionResult Tut145()
{
return View();
}
View of First
#model Testy20161006.Controllers.NewbieDevViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Tut145 - View 1</title>
</head>
<body>
#using (Html.BeginForm())
{
#Html.LabelFor(r=>r.DataToPassToNewControllerAction)
#Html.TextBoxFor(r => r.DataToPassToNewControllerAction, new { #Value = "ValueOfData" })
<input type="submit" value="Submit data - to send to new Controller Action" />
}
</body>
</html>
Controller of Second
namespace Testy20161006.Controllers
{
public class Home2Controller : Controller
{
//I named my Controller Home2 and Action MyAction2, but you can name it anything you want
public ActionResult MyAction2(string passedData)
{
//reconstruct the ViewModel and pass into second view
NewbieDevViewModel viewModel = new NewbieDevViewModel { DataToPassToNewControllerAction = passedData };
return View(viewModel);
}
View of Second
#model Testy20161006.Controllers.NewbieDevViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>MyAction2 </title>
</head>
<body>
<div>
- Final View - I passed data into here from different Controller Action -and-
I can render this page anyway I which
</div>
<p/>
#Html.LabelFor(r => r.DataToPassToNewControllerAction)
#Html.TextBoxFor(r => r.DataToPassToNewControllerAction)
</body>
</html>
Partial view can be used to render a view inside another view. Create a partial view for an action in controller 2. Call that partial view from the view of controller 1.
Here is the example :
First Controller :
public class Controller1Controller : Controller
{
public ActionResult Edit()
{
return View();
}
}
First Controller View :
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Controller 1 View</h4>
<hr />
<h1>Fisrt Controller</h1>
<div>
#{
Html.RenderAction("GetSubject", "Controller2");
}
</div>
</div>
}
Second Controller :
public class Controller2Controller : Controller
{
public ActionResult GetSubject()
{
Subject s = new Subject() { id = 2, SubjectName = "XYZ" };
return PartialView(s);
}
}
Second Controller View :
<div>
<h4>Controller 2 view</h4>
<hr />
<h1>Second Controller</h1>
</div>
After spending some time on the code and a bit of googling, I figured out my issue.
The child action method I was calling from parent view was an async method, so I did something like the below,
Parent view
<div id="childView"></div>
Ajax Call to populate the parent view
$(document).ready(function () {
$.ajax({
type: 'GET',
url : '#Url.Action(actionName: "ChildAction", controllerName: "ChildController")',
dataType: "html",
async:true,
success: function (result) { $("#childView").html(result); }
});
});
Hope it will be useful for some one.
I am trying to get a clear mental picture on how an ASP.NET Core Razor application works. So I created an empty project template and tried to recreate the original "Razor Pages Template". After learning a lot of things the hard way, It seems just impossible to get a submit button to work. Take a look at some of my code:
Create.cshtml
<p>#Model.Message</p>
<h2>Create a new customer.</h2>
<p>Enter you name.</p>
<div asp-validation-summary="All"></div>
<form method="post">
<div>Name: <input asp-for="Customer.Name" /> </div>
<input type="submit" />
</form>
Create.cshtml.cs
public class CreateModel : PageModel
{
public AppDbContext DB { get; }
[BindProperty]
public string Message { get; set; }
public CreateModel(AppDbContext db)
{
DB = db;
}
[BindProperty]
public Customer Customer { get; set; }
public void OnGet()
{
Message = "This is from the get method";
}
public IActionResult OnPost()
{
Message = "This is from the post method";
if (!ModelState.IsValid)
return Page();
DB.Customers.Add(Customer);
DB.SaveChanges();
return RedirectToPage("/Index");
}
}
Most of that code is from (MSDN Docs), It works if I create a Razor Template and then delete, and arrange everything to my taste. But when I create a project without the template, the button brings up a 404 error. Also, commands like asp-validation-summary are not made bold like they normally are when I'm using the razor pages template.
If you want to use Razor pages, you have to include a #page directive on the top of your page, otherwise it returns 404 Not Found.
#page
#model CreateModel
<p>#Model.Message</p>
<h2>Create a new customer.</h2>
...
I am unable to make a simple MVC 3 controller/view/model program work with an ActionResult method that includes the Bind attribute with a Prefix property.
One example that I did try could populated the parameter when I call the action method from the URL.
Here is that example controller followed by its view:
//Controller
//public ActionResult PrefixExample(int number = 0)
public ActionResult PrefixExample([Bind(Prefix="okay")]int? number)
{
return View(number);
}
//View
#model Int32?
#{
ViewBag.Title = "Example";
}
<h2>Example</h2>
#using (Html.BeginForm())
{
if (#Model.HasValue)
{
<label>#Model.Value.ToString()</label>
} else {
<label>#Model.HasValue.ToString()</label>
}
<input type="submit" value="submit" />
}
If I use this url http://localhost/MVCApp/Home/Example?okay=3 the parameter, number, is populated. If I use this url http://localhost/MVCApp/Home/Example?number=3, the parameter isn't populated. Interestingly, with the first url, when I view source, the prefix okay doesn't show up.
If I uncomment the first line of my controller and comment out the second line, the opposite is true: the url with okay won't populate number but the second url using number will populate number in the controller.
I would like to know how to make the following example accept a url and correctly set the "view source" prefix. Here is a possible url http://localhost/MVCApp/Home/SpecificPerson?PersonId=0&FirstName=Joe&LastName=Doe
Note, that if I remove the Bind attribute from the controller method, the above url will work with the MVC app below.
Here is my model/controller/view:
//model:
namespace MVCApp.Models
{
public class Person
{
[HiddenInput(DisplayValue = false)]
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
//controller
namespace MVCApp.Controllers
{
public class HomeController : Controller
{
public ActionResult SpecificPerson([Bind(Prefix = "myPerson")]Person aPerson)
{
return View("SpecificPerson", aPerson);
}
}
}
//view
#model MVCApp.Models.Person
#{
ViewBag.Title = "SpecificPerson";
}
<h2>SpecificPerson</h2>
#Html.EditorForModel();
<br />
#Html.EditorFor(m => m);
I would like to see the above example work. Anyone who could show me why it doesn't work as I expect or what I can do to make it work this way would be greatly appreciated.
Thank you in advance.
I think the EditorForModel brought you a bit off track. If you check the html that is generated by this helper you will see that it's not wrapped in a form. Besides that I think the EditorForModel will not serve you as much as you would like to. You can also get it to work correctly without specifying the Bind prefix.
//model
public class Person
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
//controller
public class HomeController : Controller
{
public ActionResult Index(Person person)
{
if("POST".Equals(Request.HttpMethod))
{
//for example do some validation and redirect
}
return View(person);
}
}
//view
#model Application.Models.Person //only as example use own
#using(Html.BeginForm("Index","Home", FormMethod.POST))
{
#Html.HiddenFor(x=> x.Id)
<div>
#Html.LabelFor(x=> x.FirstName)
#Html.TextBoxFor(x=> x.FirstName)
</div>
<div>
#Html.LabelFor(x=> x.LastName)
#Html.TextBoxFor(x=> x.LastName)
</div>
<input type="submit" value="Do a post request"/>
}
Also if you use a url like /Home/Index?Id=9 and you look the HTML code you will see that there will be a element with input type=hidden and the value of 9. You could also use two actionresults to split your logic with [HttpGet] and [HttpPost] as attribute of your Action.
And as last I recommend you to check out the newer versions of MVC; MVC 5 is already out...