I tried add a class attribute for a complete form. But I couldn't do it.
As the forms extends of Backbone.View I thought the correct way to get it was:
var form = new Backbone.Form({
model: myModel,
className: 'myClass'
}).render();
And also I tried:
var MyForm = Backbone.Form.extend({
className: 'myClass'
schema: {
field1: 'Text'
}
});
var form = new MyForm({
model: myModel
}).render();
But in both cases the output is:
<form data-fieldsets>
<fieldset data-fields>
//Code of form...
And I think the output would be:
<form class="myClass" data-fieldsets>
<fieldset data-fields>
//Code of form...
How about using the $el and adding it there ?
form.$el.attr("class", "testing");
live example
http://jsfiddle.net/c5QHr/228/
Related
I am using, kendo upload for multiple files. Synchronous upload. Have the same property in the mvc model as the kendo upload name, have used enctype = "multipart/form-data", still my the model property for files is null.Please help
I'm not sure that I understood the question correctly. Can you show your code and describe what exactly you want?
By the way, you don't need model to get files. You can get your file from Request.Files property in your controller. Example:
View:
<input type="file" name="files" id="files" />
<script>
$(function() {
$("#files").kendoUpload({
async: {
saveUrl: "#Url.Action("SaveFiles", "Home")",
autoUpload: false
},
showFileList: true
});
});
</script>
Controller:
public ActionResult SaveFiles()
{
foreach (string key in Request.Files)
{
var file = Request.Files[key];
}
}
I'm still learning Backbone and Marionette so forgive me if this is trivial.
I have a Backbone.Marionette.CompositeView that I iterate over to render a collection of Backbone.Marionette.ItemView.
My ItemView renders with a className: 'column'.
Is there a way to add the iterator as part of the className for each ItemView?
What I'm trying to accomplish is that the elements render as following:
<div class="column column-1"></div>
<div class="column column-2"></div>
<div class="column column-3"></div>
...
I couldn't find a suitable solution in the docs nor other questions here.
Thanks!
Essentially what you need to know is the index of the itemView model in your collection. Something like this will work:
// Create an itemView
var itemView = Backbone.Marionette.ItemView.extend({
template: "#item-template",
onRender: function () {
this.$el.addClass('class-nr-' + this.options.itemIndex);
}
});
// Create a collectionView
var colView = Backbone.Marionette.CollectionView.extend({
collection: colInstance,
itemView: itemView,
itemViewOptions: function (model, index) {
return {
itemIndex: index
};
}
});
See this fiddle: http://jsfiddle.net/Cardiff/VTkB2/2/
Documentation: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md#collectionviews-itemviewoptions
Here is what I am trying to do:
My goal is to display a list of Trending Opinions (A custom Model) from the page's model when the page loads. If a user clicks the "Show more Trending Opinions" button, it uses ajax to call a method on a controller that will then retrieve an additional number of items, come back to the page and display them. Then it adds say 20 more. Then they can repeat the process and click it again, etc.
Exactly the same as a normal site does when you click "Show More" on a list of items.
If the way I am approaching this is incorrect and you know of any tutorial (or just out of your head) showing the correct way to do this in MVC 4, please let me know. I am not dead-set on the way I am doing it at the moment, this is just the "correctest" way I have found.
I followed the answer to a similar question: How to Update List<Model> with jQuery in MVC 4
However, the data coming through to my controller is incorrect and I can't figure out what the issue is.
Let me put as much info as I can, because I have no idea where the error may be.
Model for page (OpinionModel has a few public properties):
public class IndexModel
{
public IList<OpinionModel> TopTrendingOpinions { get; set; }
}
The View:
<div id="TrendingOpinions">
<p>What is trending at the moment</p>
#using (Html.BeginForm("LoadMoreTrendingOpinions", "AjaxHelper",
method: FormMethod.Post,
htmlAttributes: new { #class = "form-horizontal", id = "LoadTrendingOpinionsForm" }))
{
#Html.EditorFor(x => x.TopTrendingOpinions)
<input type="submit" value="Load More Trending Opinions" />
}
<script type="text/javascript">
$('#LoadTrendingOpinionsForm').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: {
topTrendingOpinions: $(this).serialize()
},
success: function (result) {
alert(result);
}
});
return false;
});
</script>
</div>
**There is also an EditorTemplate for my model.
The Controller:**
[HttpPost]
public ActionResult LoadMoreTrendingOpinions(IList<MyGoldOpinionMVC.Models.OpinionModel> topTrendingOpinions)
{
var dataHelper = new Data.DataHelper();
var moreTrendingOpinions = dataHelper.LoadMoreTrendingOpinions(topTrendingOpinions.LastOrDefault().Id);
// var partialView = PartialView("../PartialViews/_ListOfPostedOpinion", moreTrendingOpinions);
return View(moreTrendingOpinions);
}
So here is the order of events:
When running the site, the form shows a list of OpinionModels (Using the Editor Template displaying correct data). When I click the SUBMIT button, it goes to the controller (I have a breakpoint) and the data for the "topTrendingOpinions" parameter is a List with one item in it, but that item is null. So in other words, it is not passing through the list that is clearly being used to populate the form.
The only way I have been able to get a list to post back to the controller is to build it manually with jquery. my understanding is this.serialize on a form click is going to try to serialize the whole from which would get very ugly. How I would do this is
<input type="button" class="btnMore" value="Load More Trending Opinions" />
$('.btnMore').on('click', function () {
$.ajax({
url: '#Url.Action("LoadMoreTrendingOpinions", "AjaxHelper")',
type: 'post',
contentType: 'application/json; charset=utf-8',
data: {
Id: '#ViewBag.Id'
},
success: function (result) {
//add results to your table
}
});
});
and set the id of the last record sent through the view bag on your controller so you have a reference to go off of for pulling the next chunk. Let me know if you have any questions
When posting lists you have to be really careful that your inputs are named correctly. If they are not, the default model binder fails to parse them into classes when posted resulting the object being null in the controller.
In your case you are posting a list of models inside a model, but not the whole model. I'd use PartialView instead of editortemplate, just to make working with field names easier. In my example we are posting a list of FooModels contained in IndexModel
Model
public class FooModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
public class IndexModel
{
public IList<FooModel> Foos { get; set; }
}
View
#using (Html.BeginForm("LoadMoreTrendingOpinions","AjaxHelper",
method: FormMethod.Post,
htmlAttributes: new { #class = "form-horizontal", id = "LoadTrendingOpinionsForm" }))
{
#Html.Partial("FooModelsPartial", Model.Foos)
<input type="submit" value="Load More Trending Opinions" />
}
FooModelsPartial
#model IList<FooModel>
#for (int i = 0; i < Model.Count(); i++)
{
#Html.EditorFor(model => model[i].Foo)
#Html.EditorFor(model => model[i].Bar)
}
Notice how we are using for instead of foreach loop. This is because editors in foreach loop are not named correctly. In this case we want our fields to be [0].Foo, [0].Bar, [1].Foo, [1]. Bar etc.
Controller:
[HttpPost]
public ActionResult LoadMoreTrendingOpinions(IList<FooModel> topTrendingOpinions)
{
// do something with toptrending thingy
var model = new IndexModel();
model.Foos = topTrendingOpinions;
return View("Index", model);
}
Now the real question in my opinion is do you really want to post the whole list of models to get bunch of new ones related to one of them? Wouldn't it be more convenient to post the id of opinion you'd want to read more of, returning partialview containing the requested more trending opinions and appending that to some element in the view with jquery?
Html:
#using (Html.BeginForm("LoadMoreTrendingOpinions","AjaxHelper",
method: FormMethod.Post,
htmlAttributes: new { #class = "form-horizontal", id = "LoadTrendingOpinionsForm" }))
{
<div id="more">#Html.Partial("FooModelsPartial", Model.Foos)</div>
<input type="submit" value="Load More Trending Opinions" />
}
Javascript:
$('#LoadTrendingOpinionsForm').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: {
id: 1 /* The id of trending item you want to read more of */
},
success: function (result) {
$("#more").html(result)
}
});
return false;
});
Controller:
[HttpPost]
public ActionResult LoadMoreTrendingOpinions(int id)
{
var moreTrendingOpinions = dataHelper.LoadMoreTrendingOpinions(id);
return PartialView("FooModelsPartial", moreTrendingOpinions);
}
I have the following problem when updating a for via AJAX after it is submitted. For some reason some hidden fields that are on the HTML that is returned are not being updated, which is weird because when I run the debugger they appeared to have the correct value.
This is the relevant part of my form
<div id="itemPopUpForm">
#{Html.EnableClientValidation();}
#Html.ValidationSummary()
<div id="formDiv">
#{ Html.RenderPartial("ItemData", Model, new ViewDataDictionary() { { "Machines", ViewBag.Machines }, { "WarehouseList", ViewBag.WarehouseList }, { WebConstants.FORM_ID_KEY, #ViewData[WebConstants.FORM_ID_KEY] } }); }
</div>
</div>
Then the partial view contains hidden fields like these which are the ones not being updated
#using (Html.BeginForm("Index", "Item", FormMethod.Post, new { id = "frmItem", name = "frmItem" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Item.SodID)
#Html.HiddenFor(model => Model.Item.ItemID) //The itemID needs updating when an item is copied
#Html.HiddenFor(model => model.Item.Delivery.DeliveryAddressID, new { #id = "delAddressID" })
And this is the javascript method that updates the form
function ajaxSave() {
if (!itemValid()) return;
popup('ajaxSplash');
$.ajax({
type: "POST",
url: '#Url.Action("Index")',
data: $("#frmItem").serialize(),
success: function (html) {
console.log(html);
$("#formDiv").html(html);
initItemPage();
alert("Item was saved successfully");
},
error: function () { popup('ajaxSplash'); onFailure(); }
});
}
The action Index returns the Partial View "ItemData" and when I check the Item Model it does have the correct value, but when I see the html returned it is still set to 0.
If you intend to modify a model property in your POST action don't forget to remove it from ModelState first, otherwise HTML helpers will use the originally posted value when rendering:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// remove the value from modelstate
ModelState.Remove("Item.ItemID");
// update the value
model.Item.ItemID = 2;
return PartialView(model);
}
I'm having the same problem and it seems like the helper HiddenFor evaluates with required unobtrusive validation even if in the model one does not annotate the property with [Required].
The HTML rendered by #Html.HiddenFor(m=>m.Step) is :
<input data-val="true" data-val-number="The field Step must be a number." data-val-required="The Step field is required." id="Step" name="Step" type="hidden" value="2">
Hence, it is why it works if we remove it from the ModelState.
Removing the property from the ModelState seems to me like a hack. I would prefer to use
<input type="hidden" id="Step" name="Step" value="#Model.Step" />
instead of the Html.HiddenFor helper.
You can also implement you own HiddenFor helper.
In an MVC3 project, i use an Html.BeginForm to post some (model-)values. Along with those i want to send an extra parameter that is not part of the form (the model) but in the ViewBag. Now, when i use a Button (code in answer here: MVC3 razor Error in creating HtmlButtonExtension), all the form values are posted but the extra parameter remains null. When i use an ActionLink, the parameter is posted but the form values are not :) Any know how i can combine the two? Thanks!
#Html.Button("Generate!", new { id = ViewBag.ProjectID })
#Html.ActionLink("Generate!", "Post", new { id = #ViewBag.ProjectID })
My advice would be to declare a new Object in your App.Domain.Model something like this
namespace App.Domain.Model
{
public class CustomEntity
{
public Project projectEntity { get; set; }
public int variableUsed { get; set; }
}
}
In your view you can acces them easily by using CustomEntity.projectEntity and CustomEntity.variableUsed.
Hope it helps
You can do something like below.
View code
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post, new { #id = "frmId", #name = "frmId" }))
{
#*You have to define input as a type button not as a sumit. you also need to define hidden variable for the extra value.*#
<input type="hidden" name="hndExtraParameter" id="hndExtraParameter" />
<input value="Submit" type="button" id="btnSubmit" onclick="UpdateHiddenValue()" />
}
<script type="text/javascript">
function ValidateUser() {
$("#hndExtraParameter").val('Assignvaluehere');
$("#frmId").submit();
}
</script>
Controller Code
[HttpPost]
public ActionResult ActionName(Model model, string hndExtraParameter)
{
//Do your operation here.
}