I know I am missing something very basic. I have a HomeController and inside that there is a partial view. There is a button inside partial view which gets data(ParserModel) via ajax call. Now the single data value is not getting in _Parser.cshtml.
Here is my HomeController ajax method which calls ParserView data.
public IActionResult Parser()
{
ParserModel parser = new ParserModel();
parser.LogoPosition = "This is correct";
return PartialView("_Parser");
}
Below is my _Parser.cshtml view which is not setting the value of LogoPosition
#using PageRefine.Models
#model PageRefine.Models.ParserModel
<form asp-controller="Home" asp-action="Parser" data-ajax="true" data-ajax-update="#CustomerList">
<button type="submit" id="button1">Click</button>
<p>#Model.LogoPosition</p>#*This is giving null reference error. Here it should be "This is correct"*#
<p>#Html.RenderPartial("_Parser", Model.LogoPosition)</p>#*This is printing LogoPosition*#
</form>
Here is Index.cshtml code for partial view
<div id="CustomerList">
<partial name="_Parser" />
</div>
What should I do to get the modal values by their name in Partial View (_Parser.cshtml). Let me know if I am missing any info.
You need to pass the model to your partial view
public IActionResult Parser()
{
ParserModel parserModel = new ParserModel();
parserModel.LogoPosition = "This is correct";
return PartialView("_Parser", parserModel);
}
Related
I'm starting to learn ASP.NET Core MVC and just found out that the toolbox is inaccessible/disabled/grayed out, so in html I cannot use <asp:Label/> tag and have to use <label></label> tag instead.
Now I am having trouble changing the string on the HTML Tag <label></label> from the backend.
For this case I already wrote runat="server" inside the tag but still an error occured that says:
The name 'lblkpj' does not exist in the current context
Here is the example html:
<label class="text-center mb-1 fw-bold" runat="server" id="lblkpj"> </label>
and C#:
if (tbl.Rows.Count > 0)
{
lblkpj.text = "Success";
}
else
{
lblkpj.text = "Failed";
}
Where am I going wrong?
Work with Razor markup.
You can implement the logic in View by declaring the variable. And use # symbol. Razor will evaluate the expression and render the output into HTML.
And make sure that you need to return the ViewModel as a List of your model objects from the Controller to View.
View
#model List<YourModel>
#{
string status = Model.Rows.Count > 0 ? "Success" : "Failed";
}
<label class="text-center mb-1 fw-bold" id="lblkpj">#status</label>
Controller
public class YourController : Controller
{
public IActionResult YourView()
{
// Mock data
List<YourModel> list = new List<YourModel>();
return View(list);
}
}
Let's say that i have a navbar with a search bar, and it appears on every single page, so when the user click on the search button, it could happend 2 things:
Refresh the page if the input is empty
Redirect to a SearchResult.cshtml and show the results...
So the controller and action who handle the HTTP POST Request are Search - SearchResult respectively. I want to get the URL from the caller because the action method will need it to decide what page should redirect it.
PD: I'm using ASP.NET CORE MVC 3.1
In the Layout page, you could add a hidden field to store the current page URL, then, when click the Search button, in the SearchResult action, you could get the previous URL from the hidden field. Code as below:
_Layout.cshtml page,
<div class="search">
#{
//get current url
Uri currenturl = new Uri(String.Format("{0}://{1}{2}{3}", Context.Request.Scheme, Context.Request.Host, Context.Request.Path, Context.Request.QueryString));
}
<form asp-controller="Search" asp-action="SearchResult">
<input class="text-body" type="text" value="" name="search" />
<input name="returnurl" type="hidden" value="#currenturl" />
<input type="submit" class="btn btn-info" value="Search" />
</form>
</div>
Code in the SearchResult action:
public IActionResult SearchResult()
{
//get the returned url
var returnurl = HttpContext.Request.Form["returnurl"].ToString();
//do something
return Redirect(returnurl);
}
The screenshot as below:
What you probably want to do is submit the current path/query along with your query.
You could accomplish that by having your search form be something like this.
<form asp-controller="Search" method="get">
<input name="q" value="#Context.Request.Query["q"]" />
<input name="r" type="hidden" value="#Context.Request.GetEncodedPathAndQuery()" placeholder="Search the thing" />
</form>
Notice im using a get method here. This is to keep the search state in the browser but you can manage that however you need too. Im also using GetEncodedPathAndQuery which will need to be installed, but again the important part is to maintain the path/query(and more if this will be cross domain).
My controller will then look something like this.
[Route("/search")]
public class SearchController : Controller
{
[HttpGet]
public IActionResult Index(
[Bind(Prefix = "q")] string query,
[Bind(Prefix = "r")] string referrer)
{
IActionResult result = null;
if (string.IsNullOrWhiteSpace(query))
{
result = this.Redirect(referrer);
}
else
{
result = this.View(); // do search and return view.
}
return result ?? this.Redirect("/");
}
}
This can obviously be adjusted in anyway you need. The main thing is accepting the two values from the request and handling them properly. You might also want to validate that the referrer is an actual url since the redirect action will throw if its not.
I would like to have two buttons in my view (called Create), one that submits the form and takes the user back to home page if they are finished and one that submits the form but reloads the rating page to be able to add additional ratings.
Here is the problem that I have right now-
Currently I have one button that has an action result in my controller:
public ActionResult Create(Rating rating)
{
if (ModelState.IsValid)
{
db.Ratings.Add(rating);
db.SaveChanges();
return RedirectToAction("Index");
}
**Additional code that is irrelevant here
}
The problem that I am faced with is that this ActionResult has a Redirect in it to the homepage so when I submit my other button and use this same ActionResult class it is being redirected to the homepage. I am using the javascript onclick event in the view to redirect to the Ratings page when the button is clicked and the form is submitted but if I use this same Action Result class for both buttons it redirects the button I want to keep me on the page to the index page.
How do I create two Action Result classes from the same view, one for each submit button?
Well, how do you determine what the user wants to do?
Both buttons submit the form, so they may as well still use the same action. But you need to differentiate somehow. You can do that with the buttons.
Let's say you have these two buttons:
<input type="submit" name="redirect" value="true" />
<input type="submit" name="redirect" value="false" />
Then you can bind that in your action method:
public ActionResult Create(Rating rating, bool redirect)
{
// other logic
if (redirect)
return RedirectToAction("Index");
else
return View(rating);
}
If you are ever going to have more than two possible options then you might use a string instead of a boolean. Something like:
<input type="submit" name="action" value="redirect" />
<input type="submit" name="action" value="reload" />
And then in the controller:
public ActionResult Create(Rating rating, string action)
{
// other logic
if (action.Equals("redirect"))
return RedirectToAction("Index");
else if (action.Equals("reload"))
return View(rating);
else if //...
//... and so on
}
The point is that the client-side code needs to tell the server-side code what to do somehow. Including that on the form submission itself makes the form submission self-describing and allows the server-side code to handle it easily.
Example of how it use
Html, inside form:
<button type="submit" name="TaskSubmitAction" value="ActionReject" class="btn btn-danger pull-left">Reject</button>
<button type="submit" name="TaskSubmitAction" value="ActionSubmit" class="btn btn-success">Accept</button>
Controller:
public ActionResult TaskSubmit(int? id, string TaskSubmitAction)
{
switch (TaskSubmitAction)
{
case "ActionSubmit":
break;
case "ActionReject":
break;
default: throw new Exception();
}
In your html give both buttons the same 'name' attribute but assign two different values.
<button name="submitBtn" value="valueX"> Button 1 </button>
<button name="submitBtn" value="valueY"> Button 2 </button>
In your server side code get the value of the input button and based on this value carry out different actions
String choice = request.getParamter("submitBtn");
if(choice.equals("valueX"))
//do something
else if(choice.equals("valueY"))
//do something else
If I do the following
ViewModel:
public class ToleranceInput{
public decimal Tolerance{get;set;}
}
And in my views
AssignTolerances.cshtml
#model ToleranceInput
#using (#Html.BeginForm("AssignTolerances", Tolerances", FormMethod.Post, new {#class="form-horizontal"}))
{
#Html.ValidationSummary()
#Html.Partial("_AssignOrEditTolerances", Model)
<div class="form-actions">
<button type="submit">
<i class="icon-ok icon-white"></i> Save
</button>
</div>
}
_AssignOrEditTolerances.cshtml:
#model ToleranceInput
#Html.TextBoxFor(a=>a.Tolerance)
#Html.ValidationMessageFor(a=>a.Tolerance)
The standard MVC validation works correctly. When I type in letters (instead of numbers) it shows a red error message as it should. However, in the viewmodel if I change Tolerance to a nullable decimal? it does not work correctly. if I type a non-decimal such as 'asdf' in the textbox I see a quick flash of the red validation messsage when I hit the save button, but then the POST goes through and the [HttpPost] AssignTolerances method in my controller gets executed. Why is this happening? Any ideas?
Edit: I have just found the following link. Looks like the strings get converted to nulls and the workaround looks horrible: Integer validation against non-required attributes in MVC
Have you also considered adding the check in the controller action?
[HttpPost]
public ActionResult TestPost(ToleranceInput model)
{
if(!ModelState.IsValid)
{
return View(model);
}
}
And then simply add validation into your Model, such as the [Required] attribute
Sitecore 7.1v1, most recent Glass Mapper, MVC4. When we submit the form POST, we get no layout with the return View. I'd prefer not to have to redirect to another page since this is supposed to be a wizard-like experience. This is also lightweight enough not to require Ajax, although we could use it as a last resort. I can't find who to make sure that while returning the View that we get the layout as well. I'm new to Sitecore MVC and pretty new at MVC in general. The PageBase that's referenced is a Custom Model using Glass.
We have the following Controller Rendering:
public class RegistrationController : Controller
{
[HttpGet]
public ActionResult VerifyAccount()
{
return View("~/Views/Public/Wizards/Registration/VerifyAccount.cshtml",
new SitecoreContext().GetCurrentItem<PageBase>());
}
[HttpPost]
public ActionResult CreateProfile()
{
ViewBag.Name = Request["VerificationType"];
ViewBag.Step = 2;
return View("~/Views/Public/Wizards/Registration/CreateProfile.cshtml",
new SitecoreContext().GetCurrentItem<PageBase>());
}
}
The default action for this is VerifyAccount(). This renders as expected. The initial view is as follows:
#inherits Glass.Mapper.Sc.Web.Mvc.GlassView<Public.Model.GlassModel.Primary.PageBase>
<div>
<h3>#Editable(a => a.Title)</h3>
<p>
#Editable(a => a.Description)
</p>
<hr />
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{
#Html.Sitecore().FormHandler("Registration", "CreateProfile")
#Html.ValidationSummary(true, "Verification Not Selected.")
<fieldset>
#Sitecore.Globalization.Translate.Text("$Registration.VerificationTitle")
#{ var validations = new SitecoreContext().GetItem<GlassFrameBase>(Guid.Parse("{3694FC43-3DB7-470A-A1E9-2649856AAF10}"));}
<select id="VerType" name="VerificationType">
#foreach (var validation in validations.GetChildren<VerificationMethod>())
{
<option value="#validation.MethodValue">#validation.MethodName</option>
}
</select>
<input type="submit" value="Next" />
</fieldset>
}
This posts back to the CreateProfile() Method. This part works great. The only issue is that when it returns the view this time, it returns just the view without the layout.
The final view is as follows:
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{
#Html.Sitecore().FormHandler()
<p>
<b>Verification Type Was: </b>#ViewBag.Name
</p>
<p>#ViewBag.Step</p>
<input type="hidden" value="ThisIsATest" name="TestHidden" id="TestHidden"/>
<input type="submit" name="back" value="Back" /><br />
<input type="submit" name="next" value="Next" />
}
Everything else is working exactly as expected but I'm missing something important that loads the Layout on the return trip.
I have noticed this before as well and I think it relates to this line:
#Html.Sitecore().FormHandler("Registration", "CreateProfile")
It seems to bypass the standard rendering pipeline and just call the target action. I have written a blog post on how you can control calls to different action on multiple controllers. this might help:
http://www.experimentsincode.com/?p=425
Try changing the return type of CreateProfile from ActionResult to PartialViewResult, and then return View("... to return PartialView("...
Also, here's a post about what you can return for Sitecore Controller Renderings.
http://mhwelander.net/2014/04/09/sitecore-controller-rendering-action-results-what-can-i-return/
I haven't looked deeply into form posting with Controller Renderings, but if the above suggestion doesn't work then maybe consider the execution lifestyle used in Sitecore MVC (mentioned in the post).