This question is an extension of this Related question.
Taking Derick's advice, I now have my data in the correct shape. i.e. I have a collection of Department objects, each of which have a collection of Users.
Again following Derick's advice I'm trying to render a CollectionView of CompositeView's
My collection view looks like this
class UserListView extends Backbone.Marionette.CollectionView
itemView: UserCompositeView
id: "user-list"
appendHtml: (collectionView, itemView, index) =>
itemModel = #collection.at(index)
itemView = new UserCompositeView
model: itemModel
collection: itemModel.get("users")
collectionView.$el.append itemView.el
and my Composite View looks like this:
class UserCompositeView extends Backbone.Marionette.CompositeView
itemView: UserItemView
itemViewContainer: '#users'
If I don't override the appendHtml method then the view renders but it only renders the properties of the Department model. It doesn't render the users collection.
When I override the appendHtml method in the CollectionView so I can pass a model (a Department object) and a collection of users but one or both of them seem to be the wrong type of objects because the Marionette bindTo function is complaining that the object has no 'on' method.
What am I doing wrong?
What does itemModel.get("users") return?
If this is returning a JavaScript array or object literal, that would be the problem. You have to pass a valid Backbone.Collection as the collection parameter, not just an array of objects.
collection: new Backbone.Collection(itemModel.get("users"))
You can also look into using backbone-relational which will let you define models that have submodels or subcollections.
Related
When is goto edit data screen apply a model to fill data if user do make some changes but press back button the model saves the data? I am assigning the model to another demo model but it reflects the changed values.
You can create copy method in reference class and assign it's property on back action.
Override your model init method like below.
required override init() {
}
required init(_ model: Person) {
// Assign your Values
}
Use it Like
let obj = People(model : Person)
to copy
Either you can implement copyable protocol in your class model and assigning copy of that model.
or
Create struct instead of class.
I am using Entity Framework code first with a generic repository pattern with ASP.NET MVC. I have two tables Category and Product.
My model class of product is like this
Public class Product
{
public int ProductID{get;set;}
Public int CategoryID{get;set;}
[ForeignKey("CategoryID")]
public virtual Category Category{get;set;}
[NotMapped]
public string CategoryName{get;set;}
}
The model is binding correctly as long as I am getting data using DBContext.
But I am having a problem when I am getting list of products from stored procedure mapped to Product object. So it is not mapping the Category property of Product object and hence I cannot able to get Category.CategoryName.
So I added a new property with [NotMapped] attribute in product class as CategoryName. But it is also not binding from stored procedure.
And if I remove the [NotMapped] attribute then it is correctly binding from stored procedure but error occurs again when getting product by DbContext (Linq).
Please help me in this regards.
You don't need to add an extra property, use the DbSet.SqlQuery method for queries that return entity types. The returned objects must be of the type expected by the DbSet object, and they are automatically tracked by the database context unless you turn tracking off.
var products= _context.Products.SqlQuery("storedProcedureName",params);
The columns returned by SP should match the properties of your entity type otherwise, it will throw an exception.
After execute your SP, you should be able of get the CategoryName through your Category navigation property:
var catName=someProduct.Category.CategoryName;
On the other hand, the returned data by the Database.SqlQuery isn't tracked by the database context, even if you use this method to retrieve entity types. If you want to track the entities that you get after execute your SP using this method, you can try this:
//Attach the entity to the DbContext
_context.Product.Attach(someProduct);
//The Category navigation property will be lazy loaded
var catName=someProduct.Category.CategoryName;
If you have disabled lazy loading you can load explicitly your navigation property:
//Load the Category navigation property explicitly
_context.Entry(someProduct).Reference(c => c.Category).Load();
Very simple question: in a strict MVC design pattern we want to keep Model, View and Controller can the View layer know which custom data classes are defined in the model?
As example:
I got a CarViewController in the view layer and a Car object in the model layer. Whenever the model layer changes the controller object that "sits" between the model and the view notifies the CarViewController and in my current implementation passes a copy of the updated car data as an instance of the Car class. Is this correct?
My gut instinct would have said no because I would not want the view layer to know the details of the model objects. It is not strict decoupling. However if I pass specific values instead of passing the custom data model I would need to stick to standard/primitive values (E.g. int as number of wheels) and it may require more coding.
Have I understood MVC correctly? Is there any reason why the view should not know the custom classes of the model layer?
If I am understanding your question correctly, I would say that your view needs to know the details of your Car object in most of the cases. You can utilize metadata in this way like this:
Model:
public class Car
{
[Display(Name = "Number of wheels")]
public int Wheels { get; set; }
}
View:
#model Namespace.Models.Car
#* This will display whatever your [Display(Name="Value")] decorator defines
as a display name, also the editor will respect the data type decorator. *#
#Html.LabelFor(m => m.Wheels)
#Html.EditorFor(m => m.Wheels)
In this case if you basically pass down a primitive then all metadata for your model is lost.
I've found a property of my helper that I think will give me access to the properties of my model, but I was hoping to get an instance of the model itself. I have a view with a strongly typed Model. One property of the model, is a collection of other models (TestModel). I would like to render each of the items in the collection in a standard way. So, my view code would look something like this.
#foreach(var testModel in #Model.Items){
#Html.DisplayViewerFor(#testModel)
}
My helper looks something like this.
public static MvcHtmlString DisplayViewerFor(this HtmlHelper<TestModel> helper, Expression<Func<TestModel>> expression, bool rightAligned = true) {
var modelData = helper.ViewData;
var prop = modelData[""];
var outterDiv = new TagBuilder("div");
outterDiv.AddCssClass(rightAligned ? "item-display-right" : "item-display");
//Create other markup using modelData here
//Would prefer to use an instance of TestModel
return new MvcHtmlString(outterDiv.ToString(TagRenderMode.EndTag));
}
It sounds like you want a value, not an expression.
Extend the non-generic HtmlHelper class and take a raw TestModel instance as a parameter.
You only need an expression tree if you want to find out the property name.
I hope I'm not missing something incredibly obvious here but is there any reason why model binder is always having trouble binding a view model that inherits from a collection?
Lets say I want to show a paged list and display a combo box and add button above it (dealing with simple lists). Involved classes would look like:
public class PagedList<T> : List<T>
{
public int TotalCount { get; set; }
}
And then a view model that looks like:
public class MyViewModel : PagedList<ConcreteModel>
{
public IEnumerable<ChildModel> List { get; set; }
public int? SelectedChildModelId { get; set; }
}
So in the view (Razor):
#model MyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.SelectedChildModelId, new SelectList(Model.List, "ChildModelId", "DisplayName"))
}
And the controller HttpPost action:
public ActionResult(MyViewModel viewModel)
{
...
}
The above will cause viewModel in ActionResult to be null. Is there a logical explanation for it? From what I can tell it's specific only to view models that inherit from collections.
I know I can get around it with custom binder but the properties involved are primitive types and there isn't even any generics or inheritance.
I've reworked the view models to have the collection inherited type as properties and that fixes the issue. However I'm still scratching my head over why the binder breaks down on it. Any constructive thoughts appreciated.
To answer my own question: All my models that have anything to do with collections no longer inherit from generic list or similar but instead have a property of the required collection type. This works much better because when rendering you can use
#Html.EditorFor(m => m.CollectionProperty)
And create a custom editor under Views/Shared/EditorTemplates for contained type. It also works beautifully with model binder since all individual items from collection get a index and the binder is able to auto bind it when submitted.
Lesson learned: if you plan to use models in views, don't inherit from collection types.
Sometimes model binding to a collection works better if the data in the form post is formatted differently.
I use a plugin called postify.
http://www.nickriggs.com/posts/post-complex-javascript-objects-to-asp-net-mvc-controllers/