how to share a model between different views with Backbone Marionette? - marionette

What is the simple way to share a model between two views ?
For example, in a simple mail app, my model contains for each message, the sender, the title, and the content of the mail. One of the view is the list of the messages with only the sender and the title. When you click on the title a new view is displayed with the content.

This is straight forward and requires no magic. Simply set the same model on multiple views. Something like this following:
var MyMailView = Backbone.Marionette.ItemView.extend({}),
MyOtherMailView = Backbone.Marionette.ItemView.extend({}),
modelInstance = new Backbone.Model();
var view = new MyMailView({model : modelInstance}),
otherView = new MyOtherMailView({model : modelInstance});
Now you have a model shared between two views.

Related

Use NavigateAsync in Prism.Forms with an already existant ViewModel

Scenario: I have view, view model and model for PickList and PickLine. The PickListViewModel contains an ObservableCollection<PickLineViewModel> and the PickList model contains a List<PickLine>. My PickList page contains a ListView which is bound to the ObservableCollection<PickLineViewModel> and if a line is tapped NavigateAsync is called to navigate to the tapped PickLine.
Normally, when I call NavigateAsync Prism navigates to the page, locates the view model, creates an instance of it and binds this instance to the view. But in this case the view model instance that should be bound to the page is already existant (as an element of my ObservableCollection) and I don't want the Prism ViewModelLocator to create a new instance, due to the fact that it then would have to get data from web service and I try to keep the number of web service calls as low as possible.
Also I can't use models in the ObservableCollection because the view model contains properties which are only used for UI purposes so these properties should definitely not be part of the model, but the UI properties I'm talking about are needed in the PickList page and in the PickLine page.
Tl;dr: Is there any way in Prism.Forms to provide a view model instance
on navigating to a page that will than be bound to it?
Your problem is that you are confusing what a Model is and what a ViewModel is. In this case what you should have is:
PickLine (Model)
PickLineView (View)
PickLineViewModel (ViewModel)
PickLineListView (View)
PickLineListViewModel (ViewModel)
Containing your ObservableCollection of PickLine not PickLineViewModel
Without seeing your precise code, I'm going to take a guess from experience here that your code probably looks something like the following in principal:
public ObservableCollection<PickLineViewModel> Items { get; set; }
public DelegateCommand<PickLineViewModel> ItemTappedCommand { get; }
public void OnNavigatedTo(INavigationAware parameters)
{
var picks = _dataService.GetPickLines();
Items = new ObservableCollection<PickLineViewModel>(
picks.Select(x => new PickLineViewModel
{
Model = x,
ItemTappedCommand = ItemTappedCommand
});
}
I see code like the above a lot from people who confuse the difference between a Model and ViewModel, and often from people who don't understand how to properly bind back to the ViewModel from something like a Cell in a ListView.
What you should have instead is code that is more like:
public ObservableCollection<PickLine> Items { get; set; }
public DelegateCommand<PickLine> ItemTappedCommand { get; }
public void OnNavigatedTo(INavigationAware parameters)
{
var picks = _dataService.GetPickLines();
Items = new ObservableCollection<PickLine>(picks);
}
Is there any way in Prism.Forms to provide a view model instance on navigating to a page that will than be bound to it?
No, as far as I know, Prism Forms does not provide view model-first navigation (as opposed to Prism on WPF which does).
You should be able to work around this, though, by passing your existing view model as parameter and making the ViewModelLocator-created view model an "empty shell" that redirects everything to the actual view model.

How do I bypass the limitations of what MVC-CORE controllers can pass to the view?

From what I've read, I'm supposed to be using ViewModels to populate my views in MVC, rather than the model directly. This should allow me to pass not just the contents of the model, but also other information such as login state, etc. to the view instead of using ViewBag or ViewData. I've followed the tutorials and I've had both a model and a viewmodel successfully sent to the view. The original problem I had was that I needed a paginated view, which is simple to do when passing a model alone, but becomes difficult when passing a viewmodel.
With a model of
public class Instructor {
public string forename { get; set; }
public string surname { get; set; }
}
and a viewmodel of
public class InstructorVM {
public Instructor Instructors { get; set; }
public string LoggedIn { get; set; }
}
I can create a paginated list of the instructors using the pure model Instructor but I can't pass InstructorVM to the view and paginate it as there are other properties that aren't required in the pagination LoggedIn cause issues. If I pass InstructorVM.Instructors to the view, I get the pagination, but don't get the LoggedIn and as this is just the model, I may has well have passed that through directly.
An alternative that was suggested was to convert/expand the viewmodel into a list or somesuch which would produce an object like this that gets passed to the view
instructor.forename = "dave", instructor.surname = "smith", LoggedIn="Hello brian"
instructor.forename = "alan", instructor.surname = "jones", LoggedIn="Hello brian"
instructor.forename = "paul", instructor.surname = "barns", LoggedIn="Hello brian"
where the LoggedIn value is repeated in every row and then retrieved in the row using Model[0].LoggedIn
Obviously, this problem is caused because you can only pass one object back from a method, either Instructor, InstructorVM, List<InstructorVM>, etc.
I'm trying to find out the best option to give me pagination (on part of the returned object) from a viewmodel while not replicating everything else in the viewmodel.
One suggestion was to use a JavaScript framework like React/Angular to break up the page into a more MVVM way of doing things, the problem with that being that despite looking for suggestions and reading 1001 "Best JS framework" lists via Google, they all assume I have already learned all of the frameworks and can thus pick the most suitable one from the options available.
When all I want to do is show a string and a paginated list from a viewmodel on a view. At this point I don't care how, I don't care if I have to learn a JS framework or if I can do it just using MVC core, but can someone tell me how to do this thing I could do quite simply in ASP.NET? If it's "use a JS framework" which one?
Thanks
I'm not exactly sure what the difficulty is here, as pagination and using a view model aren't factors that play on one another. Pagination is all about selecting a subset of items from a data store, which happens entirely in your initial query. For example, whereas you might originally have done something like:
var widgets = db.Widgets.ToList();
Instead you would do something like:
var widgets = db.Widgets.Skip((pageNumber - 1) * itemsPerPage).Take(itemsPerPage).ToList();
Using a view model is just a layer on top of this, where you then just map the queried data, no matter what it is onto instances of your view model:
var widgetViewModels = widgets.Select(w => new WidgetViewModel
{
...
});
If you're using a library like PagedList or similar, this behavior may not be immediately obvious, since the default implementation depends on having access to the queryset (in order to do the skip/take logic for you). However, PagedList, for example has StaticPagedList which allows you to create an IPagedList instance with an existing dataset:
var pagedWidgets = new StaticPagedList<WidgetViewModel>(widgetViewModels, pageNumber, itemsPerPage, totalItems);
There, the only part you'd be missing is totalItems, which is going to require an additional count query on the unfiltered queryset.
If you're using a different library, there should be some sort of similar functionality available. You'll just need to confer with the documentation.

MvvmCross passing data from One viewmodel to another viewmodel

I am working on Xamarin Android Application.I am using MvvmCross pattern for ViewModels.
Now,I want to pass data from one ViewModel to another viewmodel but don't want to navigate to that ViewModel. Instead of navigating to that ViewModel I want to navigate to another ViewModel.
e.g: I have three ViewModels V1,V2 and V3.Now I want to pass data from V1 to V2 but want to navigate to V3.
Is that possible ?
Look into the MvvmCross Messenger to do this: https://github.com/MvvmCross/MvvmCross-Plugins/tree/master/Messenger
You need to subscribe for something on your viewmodel:
public class LocationViewModel
: MvxViewModel
{
private readonly MvxSubscriptionToken _token;
public LocationViewModel(IMvxMessenger messenger)
{
_token = messenger.Subscribe<LocationMessage>(OnLocationMessage);
}
private void OnLocationMessage(LocationMessage locationMessage)
{
Lat = locationMessage.Lat;
Lng = locationMessage.Lng;
}
// remainder of ViewModel
}
An alternative to the mentioned messenger plugin I would suggest to save the data you need to share in a "service", being the service a singleton class managed by MvvmCross:
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
In your view models you can use that singleton just by adding it to the constructor:
public WhateverViewModel(IService service)
The service will be singleton so your data will persists over the application live cycle.
So, in one of your view models you could do:
service.SharedData = new SharedData();
In another view model:
this.data = service.SharedData
The easiest way to do this is using the Messenger Plugin from MvvmCross.You can subscribe a certain kind of message in V2 and publish that message in V1 and then navigate to V3 in a seperate step.
// subscribing to a certain message type
this.logoutToken = this.messenger.Subscribe<LogoutMessage>(this.HandleLogoutMessage);
// Creating and sending a message
var logoutMessage = new LogoutMessage(this, "You have been logged out.");
this.messenger.Publish(logoutMessage);
Note: It is important to assign the MessageToken to a member variable (like in the other answer), because otherwise it will get cleaned up by the garbage collector.

reading related data after a selection of a foreign key - MVC3 and EF4

I am new to MVC and EF and I have a question.
I have built a site with models views controllers etc.
On an edit view for a Case (pretty big model so I won't post it here) I have a FK to a Customer model using CustomerID. When a user selects a customer id from a drop down list, I would like to display CustomerName, CustomerPhone etc after the selection of the ID. I think I might need to do a post back for this to work?
Also, do I need to Include the related entities as part of the initial data "get"? I have read some detail on that but I dont fully understand how that needs to work.
Please let me know if I should post more info. Thanks!
Here is my ActionResult for Edit
public ActionResult Edit(int id)
{
Cases cases = db.Cases.Find(id);
//related data needs to loaded to show related data fields
//include related data entities
var v = db.Cases.Include("Customers");
ViewBag.TechnicianID = new SelectList(db.Technicians, "TechnicianID", "LastName", cases.TechnicianID);
ViewBag.BranchID = new SelectList(db.Branches, "BranchID", "BranchName", cases.BranchID);
ViewBag.EngineModelID = new SelectList(db.EngineModels, "EngineModelID", "EngineModelName", cases.EngineModelID);
ViewBag.CaseCategoryID = new SelectList(db.CaseCategories, "CaseCategoryID", "CategoryName",cases.CaseCategoryID);
ViewBag.Qualified = new SelectList(new[] { "YES", "NO", "PARTIALLY" });
ViewBag.CaseStatus = new SelectList(new[] { "OPEN/IN PROCESS", "CLOSED" });
return View(cases);
}
The line
var v = db.Cases.Include("Customers")
is what I am trying to use to load related customer data and then show in my edit view like this:
#Html.EditorFor(model => model.Customer.CustomerName)
Well it depends on what you are trying to do. You could include a model which holds all the required data and send it with every call on that page (initial empty ofcourse)
Once you selected the customer, do post-back and send the customerId to your application and return the same page with the desired model.
You could do that via AJAX too.
Also, do I need to Include the related entities as part of the initial data "get"?
Not sure if I understand what you are trying to say. You mean that you think you would have to send all customer's data down to the page and select the related data on client side?

MVC3 -- Adding additional items to List<> with Jquery

I have a view model that looks like this:
HomeViewModel hvm = new HomeViewModel();
hvm.Applicant = new Person();
hvm.Applicant.Residences = new List<Residence>();
hvm.Applicant.Residences.Add(new Residence() { Type = "Current" });
In my .cshtml page, I have:
<label>Street # *:</label> #Html.TextBoxFor(m => m.Applicant.Residences[0].StreetNumber)
And so on and so forth for my properties in my Residence model. However, I want the user to be able to add multiple residences(previous, secondary, other, etc). I can add the necessary form fields via jquery, however, since the model doesn't know about the new list items, I get an error about null objects. The front end may be adding numerous residences via jquery.
This is a surprisingly complex topic. Check out the blog series starting with http://ivanz.com/2011/06/16/editing-variable-length-reorderable-collections-in-asp-net-mvc-part-1/
Try this: http://archive.plugins.jquery.com/project/jquery-dynamic-form
View demo here: http://sroucheray.org/blog/jquery-dynamic-form/

Resources