First of all if this is a double post, my bad. I feel I tried my best to look for this, and I cannot find it.
What I'm trying to do is create a quick CMS editor. I have an editor page (PageViewModel class) and then, in this case, using that editor as way to create a new page (Page class).
I've been trying to go "by the book" on how to submit data via forms created in MVC 4, which is basically, through the WYSIWYG editor when adding a view and selecting Create. For it to bind the fieldset data, it needs the view model. My problem is that I don't want the form model to be based on the view model. In my scenario, I have a PageViewModel class, and I also have a Page class. Just know that the PageViewModel is composition pattern, which combines a Page with other items.
In the case here, I see everywhere using the #model to generate that content like:
<fieldset>
<legend>Page</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
How do I have fieldset generate or reference another class type other than the #model, so I can use a different model?
Thanks everyone,
Kelly
Kelly,
in your PageViewModel you can have a property that points to another ViewModel, for example:
public class PageViewModel
{
public Page Content { get; set; }
}
public class Page
{
public int Id { get; set; }
public string Foo { get; set; }
}
And then you can create a strongly typed view for "PageViewModel", that will renders a partial view named "Page":
#model MvcApplication2.Models.PageViewModel
#{
ViewBag.Title = "PageViewModel";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("Page",#Model.Content)
That is the partial view's code, it is strongly typed as well:
#model MvcApplication2.Models.Page
<fieldset>
<legend>Page</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Foo)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Foo)
#Html.ValidationMessageFor(model => model.Foo)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
You can alternatively also use the ViewData property. In your controller, your code would look like this:
public ActionResult Index()
{
Page page = new Page();
ViewData.Add("Page", page);
return View();
}
And in your view, it is almost the same:
#Html.Partial("Page", ViewData["Page"])
Create a different view that uses your new model, or make the current view take a base version of a model, e.g., an Interface or abstract (virtual) class that the other two models inherit from.
It seems like it may be a lot of work to update two forms, but if you think the two models will vary greatly, it's easier to separate them now then to try to maintain a lot of if-then code in the view later on. If they are relatively similar, why not use the method mentioned above, OR just use the same model?
Look idea is that in your view you can pass model which can be any class containing other classes or so called ViewBag.
For example, in your action method you can populate a model and pass it to the view
var model = new MyModel();
model.Text = "";
return View(model);
But if you need to pass something else and more important you don't want to include this in your model then use ViewBag.
For example, we pass Title.
ViewBag.Title = "My Page";
Idea is that viewBag is a dynamic generated object so you can add any properties to it and use them in the view later.
#ViewBag.Title
So after submitting a form you will have only model containing a user's text, but not title.
Related
I have an integer field and when i enter a non integer value (let's say a symbolic one) the Feedback panel should be triggered automatically with default message, but it does not work, I have to call it in onError method of the form by method error().
This is the textField, that i use:
RequiredTextField<Integer> intField =
new RequiredTextField<>("intValue", integerValue,Integer.class);
this is my simple FeedBackPanel:
fragment.add(new FeedbackPanel("feedback"));
it works only when i call method error() in method onError() of the form.
Could you show us how you create your Form and the Model you use? As far as I understand it you will want to bind a Model to your Fields. My best guess is that your Model does not have a property "intValue".
You might want to (re)visit the Wicket Wiki "More on Models".
I'm not sure how you are setting your model. And once you add RequiredTextField it will not allow you empty and since you set the Integer type it will not allow characters to be entered.
I have tried some code snippet which is working perfectly and validating.
HomePage.html
<html xmlns:wicket="http://wicket.apache.org">
<body>
<form wicket:id="someForm">
<div wicket:id="feedback"></div>
<input type="text" wicket:id="requiredText">
<input type="submit" value="submit">
</form>
</body>
</html>
HomePage.Java
public class HomePage extends WebPage {
private static final long serialVersionUID = 1L;
public HomePage(final PageParameters parameters) {
super(parameters);
Form form = new Form("someForm");
form.add(new FeedbackPanel("feedback"));
IModel integerValue= Model.of("");
form.add(new RequiredTextField("requiredText",integerValue,Integer.class));
add(form);
}
}
Please let me get back to me on this incase if you need anything .
I have a simple partial with a form inside which is used as a search bar.
#using (Html.BeginForm("Details", "Projects", FormMethod.Get))
{
<div class="row" style="margin-bottom: 20px;">
<div class="col-lg-3 pull-right">
<input type="search" class="form-control" placeholder="Search Code" id="projectSearch" name="code" />
</div>
</div>
}
This should post to my Projects Controller Details Action, however this isn't happening, and I believe this because of the [Route] attribute that is applied to the action, as when I comment this out, the form posts correctly. However I want to use the [Route] attribute.
The action looks like this:
[HttpGet]
[Route("{code}/Details")]
public ActionResult Details(string code)
{
if (code == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
...
return View(viewModel);
}
When the attribute is in use the form will post to this url:
/Projects/Details?code=PP61
which doesn't map to the correct action. Instead I get a resource cannot be found error.
The expected/desired url should look like
/Projects/PP61/Details
This works fine if I create a Url.Action or browse to the URL, so I know this action works, however it doesn't work with a form post. Any ideas why?
Thanks.
Change [HttpGet] to [HttpPost] on the controller and FormMethod.Get to FormMethod.Post in the view.
I have one solution to the problem, it doesn't however answer why this wasn't working in the first place. I have created a separate action which is for the search bar to POST to, this action then redirects to the GET action which I was trying to reach in the first place.
[HttpPost]
public ActionResult ProjectSearch(string code)
{
if (code != "")
{
return RedirectToAction("Details", new { code });
}
else
{
return RedirectToAction("Index");
}
}
This now works correctly, but I would still love to know why this didn't work to begin with if any body has any ideas. Cheers.
Problem:
In my application I have provide the user a selection screen for something in several places (that is, the same selection screen has to be used in several actions).
Solution:
I've come up with the following solution: pass the return action and controller to action which handles the entity selection.
Example:
Suppose that there are several places in the application where the user has to select an instance of SomeEntity, so I added the following action to that entity controller:
public class SomeEntityController : Controller
{
/* ... */
public ViewResult Select(string returnAction, string returnController)
{
var selectableEntities = ...;
return View(
new SelectionViewModel<SomeEntity>
{
Entities = selectableEntities,
ReturnAction = returnAction,
ReturnController = returnController,
});
}
}
In the view for that action (Views/SomeEntity/Select.aspx) I put something like this:
<table>
<tr>
<th>Select</th>
<th>SomeProperty<th>
</tr>
<% foreach (var entity in Model.Entities) { %>
<tr>
<td>
<%: Html.ActionLink("Select", Model.returnAction, Model.returnController, new { entityId = entity.id }) %>
</td>
<td><%: entity.SomeProperty %></td>
</tr>
<% } %>
</table>
Then, if I need the user to select a SomeEntity in other controller I can do this:
public class OtherController : Controller
{
public ActionResult SelectSomeEntity()
{
return RedirectoToAction("Select", "SomeEntity", new { returnAction = "ActionThatNeedsAnEntity", returnController = "Other" });
}
public ActionResult ActionThatNeedsAnEntity(int entityId)
{
// here I can use the selected entity
}
}
The last piece of code is just an example of how to use the SomeEntity selection action. Instead of the SelectSomeEntity action, there could be a more complex action which performs some checks to see if an entityId is already selected (e.g. stored in the session) and then decide whether to call SomeEntity/Select or not
Question:
The above works fine, but I’m new to ASP.Net MVC 2 so I don’t know if there is other (standard) solution for this.
Is this approach correct/neat? Have you solve this same situation differently?
I could be misunderstanding your problem, but I think that Partial Views would be the "standard" solution you're looking for.
Partial Views are just that, small views that can be inserted into other views. Things like entry forms or displays of data can be put into a partial view and added to the regular view. They greatly simplify code.
They're simple to make. When you go to make a regular view, just check the "partial view" box in the window (i. e. after right-clicking in the solution explorer and selecting the "add view" option). You can then throw this into any full view by using <%: Html.Partial("myPartialView") %>. You can easily pass a Model to the partial view as well by doing <%: Html.Partial("myPartialView", Model) %>
I'm pretty new to MVC 2 and I'm having problems figuring out how to post values that lies outside the form.
This is my code very simplified:
<input type="text" id="TextboxOutsideForm"/>
<% using (Html.BeginForm("Edit", "Home", FormMethod.Post)) {%>
<%: Html.ValidationSummary(true) %>
<%: Html.TextBoxFor(model => model.Stuff) %>
<input type="submit" value="Save" />
<% } %>
TextboxOutsideForm can be changed by the user and when pushing save I want to include the value from this control to the action in the controller. It would also be great if i could use model binding at the same time.
This would be great:
[HttpPost]
public ActionResult Edit(int id, Model model, string valueFromTextbox)
Or just a FormCollection and a value..
I know that in this simplified example i could just put the textbox inside of the form, but in real life the control is 3rd party and is creating loads of of other stuff, so i just need to grab the value with jquery maybe and post it..
Is this possible?
Thanks
you can have a look at this question that explains how to dynamically create the form and submit it. you can hijeck the submit event and add value into form dynamically
$(function() {
$('form').submit(function() {
$(this).append($("#ValueOutsideForm"));
return true;
});
});
this way u don't have to rely on ajax and u can post ur form synchronously.
If you use a normal form post only inputs inside the form will be sent to the server. To achieve what you are looking for you will need to submit the form using AJAX. Example:
$(function() {
$('form').submit(function() {
$.ajax{
url: this.action,
type: this.method,
data: $(this).clone().append($('#TextboxOutsideForm').clone()).serialize(),
success: function(result) {
alert('form successfully posted');
}
});
return false;
});
});
Also don't forget to give a name to the input field which is outside the form.
I have a masterpage that render's the following PartialView:
<% Html.RenderPartial("AddPage); %>
AddPage Controller looks like this:
public class PagController : Controller
{
[HttpGet]
public PartialViewResult AddPage()
{
return PartialView();
}
[HttpPost]
public PartialViewResult AddPage(FormCollection forms)
{
//some logic here
// some view data here
return PartialView();
}
}
And the view looks like this:
<% using (Html.BeginForm("AddPage", "Page", FormMethod.Post, new { ID = "PageManager" })){%>
<%= Html.TextBox("txtAddPage") %>
<input type="submit" value="AddPage" />
<%} %>
My issue is, that when i hit submit i get redirect to : http://localhost:1234/Page/AddPage, when instead i just want the partialview to be submitted, and return some basic view data if needed, as well as stay on the same page.
Am i having a blonde moment here? cause i know i have done this before
EDIT - This partial view is rendered in multiple pages, not just one.
Fullpage postback solution
This is a bit tricky since you have to know where to go back. I suggest you change your view and add two additional hidden fields (or one and parse its value - as you wish) and store current controller/action values in it.
You can then use this data in POST action to return a RedirectResult like:
return RedirectToAction("action_from_field", "controller_from_field");
Ajax postback solution
You can always submit your data using Ajax in which case your postback URL can be anything you want. In your case it should be to the current page URL. Edit: And Ajax would be the preferred solution in your particular case.
If you want to submit and only reload part of your page, you'll need to use AJAX. The most basic way to do this would be to render the partial view in an UpdatePanel.