Pass data in DurandalJS to other view - single-page-application

I'm developing a SPA webapplication with DurandalJS, but I don't understand something.
Let's say I have page 1 and 2. On page 1 there is a modal that creates a entity in the database with BreezeJS and gives back a key (that was generated in the database).
I want to pass this fetched key and then go to my second page, page 2. I know how I can do this when I put it in the url
http://localhost:60312/#/page2?orderid=2&repairorder=2
But this is not the way for Durandal, or is it? A user can enter a number of his own with al consequences!
How can I solve this?

I would like to add something to the very good #Joseph Gabriel answer. In durandal you can do this:
router.map( url: 'page2/:orderid/:repairorder',
name: 'Page2',
moduleId: 'viewModels/page2');
http://localhost:60312/#/page/2/2
But also, you can do this:
router.map( url: 'page2',
name: 'Page2',
moduleId: 'viewModels/page2');
http://localhost:60312/#/page2?orderid=2&repairorder=2
You don't nedd to specify all the parameters that you are pasing. Yo can get this parameters from the input of the active method.
var activate = function(context) {
console.log(context.orderid);
console.log(context.repairorder);
}
Sometimes the second solution can be more appropriated if you want that the user can store the url to repeat a query only copping that in the browser.

As far as I know, the only seamless way to pass parameters between view models in a Durandal app is to use the normal hash-based url parameters.
In you example, you can define a router that takes a orderId and repairOrder parameters, then your url would look something like this: http://localhost:60312/#/page/2/2
This is best option, if your data isn't too sensitive. Leave the navigation parameters in the open, and handle the values with care in the second view model. In other words, design your view model so that it can properly handle any values - even if a user directly modifies a parameter value, your view model should be able to handle it correctly.
It can be advantageous to be able to set url parameters directly, but you do have to be careful to ensure the integrity of the values before consuming them.
However, if you need to hide the parameters, you do have some different options:
Encryption: Use an encryption library like tea.js, and encrypt the value before adding it as a parameter value for navigation. Then, of course, decrypt it on the second page before using it. This allows Durandal's router navigation to work normally, while preventing users from supply their own values.
If you really need to prevent users from entering their own values, and you can bear the overhead of a few extra KB's, this is a good approach as long as you only need to pass a few parameters.
Shared data model: Use a singleton model which is shared between the two view models. This model can be manually required() as needed, and essentially serves as a repository for the application state that is shared between one or more view models.
This works fine, but it's kind of like having a big global variable - it can get messy if it's overused.
Modify VM directly: (Only for singleton view models)
Manually require() the second view model and set its properties before navigating to it.

Related

Using getInitialProps with an optional Parameter with NextJS

I have a page which allows a user to update a record, lets call it /edit-record, I want to support /edit-record/1 as a route which would load the data (I tried using getInitialProps) but I also want to make it so /edit-record is a page (ideally the same page) but without the API call to fetch the details happening.
So if I pass /edit-record/3 it should fetch record 3, if the url is /edit-record it just awaits user events.
The issue being I tried a conditional in getInitialProps, a if(query.recordId) {} but the else clause returns a null which NextJS doesnt like; it also just feels a bit wrong in terms of the approach.
What is the better way? Ideally I don't want to create two page files to handle the two conditions as all of the logic is the same.

Symfony2: Why weren't query string parameters included in the routing component?

I am porting a legacy application to Symfony2 and I am struggling because routing doesn't include query string parameters. Some quick examples: Suppose you have a search page for books where you can filter results based on criteria:
http://www.bookstore.com/books?author=Stephen+King&maxPrice=20
The nice thing about query string parameters in a case like this is you can have any number of filters, use the ones you want for any given request, and not crowd the URL with filters you're not using.
Let's say we rewrote the routing for the above query using the Symfony2 routing component. It might look like this:
http://www.mybookstore.com/book/any_title/stephen%20king/any_release_date/max_price_20/any_min_price/any_format/any_category
Even not taking into account how arbitrarily long an unclean that URL is I still don't think it is as intuitive because each 'segment' of that route is not a key value pair but instead just a value (e.g. author=Stephen+King > /stephen%20king/).
You can of course access query string parameters in the controller by passing the Request object into the action method (e.g. indexAction(Request $request) {) but then validating them and passing them into other parts of the application becomes a hassle (i.e. where I find myself now). What if you are using the Knp Menu Bundle to build your sidebar and you want parts to be marked as .current based on query string parameters? There is no functionality for that, just functionality to integrate with Symfony2 routes.
And how to validate that your query string parameters are acceptable? I am currently looking at validating them like a form to then pass them into the database to generate a query. Maybe this is the way the Symfony2 team envisioned handling them? If so I'd just really like to know why. It feels like I'm fighting the application.
I ended up actually asking Fabien this question at Symfony Live San Francisco 2012. There was another talk at the same conference in regards to this question and I will share with you the slides here:
http://www.slideshare.net/Wombert/phpjp-urls-rest#btnNext
Basically in the slides you can see that the author agrees with me in that query string parameters should be used for filtering. What they should not be used for is determining a content source. So a route should point to a product (or whatever) and query string parameters should then be used in your controller to apply whatever logic you require to filter that content source (as per Fabien).
I ended up creating an entity in my application that I bind all my query string parameters to and then manipulate, much the same way forms are handled. In fact when you think about it it's basically the same thing.
Like in Symfony1, query strings are independent from the route parameters.
If you have a path defined as #Route("/page/{id}", name="single_page"), you can create a path in your view like this:
{{ path('single_page', { id: 3, foo: "bar" }) }}
The resulting URL will be /page/3?foo=bar.

Webmatrix 2: Storing static values

Where would be the best place to store static values.
And how would I access it.
I want to be able to access static values from any page. But only have to define them in one place.
For example 'email' and 'phoneNumber'
I have tried things like Session and PageData, and defining the variables in my header (used by all pages) but this does not work.
The partial is initialised after the page, so it either doesnt work at all, or doesnt work on first time load.
E.g. First time Load:
Page Loaded <- Tries to Access variable. Not initialised.
Header Partial Loaded <- Variable initalised.
Result. Page does not show variable.
I have considered storing it in the config file. But I have no idea how to access this from Webmatrix 2.
I could just create a txt/ini file or something but surely parsing a file isn't the best way to do it. - I have since tried this and it doesnt seem valid like in mvc3 (config),and txt files are not practical to read for each request.
By "static", if you mean values that don't change across the lifetime of the application, you would normally use HelperPage.App property for storage. It is based on the dynamic type so you can create arbitrary properties:
App.Email = "someone#somewhere.com";
Or you can use the more traditional name/value collection approach with AppState:
AppState["email"] = "someone#somewhere.com";
However, if your "static" variables are user-specific, you should use Session as that is scoped to the user. Or use a database if you want to store them permanently.
You can set session values in _PageStart.cshtml (may need creating), or in the Session_Start event of the global.asax file and then access them in any partial / view you desire.

How to get an item in a collection with extra attributes

I currently get an item in a collection for a user like so:
me.user = Backbone.Collection.Users.collection().get(id);
This returns the default set of attribute required in the app. On the user profile page, I want to show additional attributes that aren't necessary anywhere else.
How can I get an item in a collection (which queries the server) with additional attributes that I can specify?
Thanks
So to go along with the comment, what I think you want is to produce extra models instead of creating two user models, one with redundant + extra data.
One way you could do this is to give a relationship between different models.
Say a user model consists of simply a name and email. That's fine and dandy but you also want to render a user profile on the page (or whatever 'extras' you intend.) This seems like a good opportunity to create a separate model representing the extra data you desire.
You can do it a few ways. For example, if every user has a profile you could bake it into your user model. Something like when you create a user model:
user.profile = new Profile(); // model
I've seen some people put other models inside a model's attributes user.set('profile', new Profile()) but I'm not sure if this is a great idea. I like to keep my model attributes isolated to just that model.
Each profile model would have a url that corresponds to the model.id.
So then you could just user.profile.fetch() and use that profile attributes to populate the data in your view. Maybe it does something like /user/1/profile
Another aspect about your question that I think you might be alluding to is sending data from the server in one go when you fetch the collection. Maybe your server replies with data like this:
[{"name":"Jake", "email":"j#stack.com", "profile":"{"aboutme":"Some story"}"}, ... ]
and the profile data is only available for those who have it etc. In this case, you can then use the parse() function to pull out that extra data out and doing something before sending the name and email attributes through to the model set method.
Although, recently I think I read that using the parse to do stuff with the extra data is bad form. Override set So instead of parsing, you might just want to save that for namespacing and then in your overridden set method do something like:
set: function(attributes, options) {
if (!_.isUndefined(this.profile) && attributes.profile) {
this.profile = new Profile();
this.profile.set(attributes.profile);
} else if (attributes.profile) {
this.profile.set(attributes.profile);
}
delete attributes.profile;
return Backbone.Model.prototype.set.call(this, attributes, options);
}
You can do something similar for really unique users such as the main user using your app. When I instantiate a user model for my app (the one representing user him/herself) I also initialize a few other special models only that user would have (like an auth model for fetching authentication data etc.)
I'm not sure if I hit what you were asking but I hope I hit something.
Is collection an instance already, and I assume so? If so, you should only do:
me.user = Backbone.Collection.Users.collection.get(id);
I.e. removing the brackets () after collection.

ASP.NET MVC routing based on data store values

How would you tackle this problem:
I have data in my data store. Each item has information about:
URL = an arbitrary number of first route segments that will be used with requests
some item type = display will be related to this type (read on)
title = used for example in navigation around my application
etc.
Since each item can have an arbitrary number of segments, I created a custom route, that allows me to handle these kind of requests without using the default route and having a single greedy route parameter.
Item type will actually define in what way should content of a particular item be displayed to the client. I was thinking of creating just as many controllers to not have too much code in a single controller action.
So how would you do this in ASP.NET MVC or what would you suggest would be the most feasible way of doing this?
Edit: A few more details
My items are stored in a database. Since they can have very different types (not inheritable) I thought of creating just as many controllers. But questions arise:
How should I create these controllers on each request since they are related to some dynamic data? I could create my own Controller factory or Route handler or possibly some other extension points as well, but which one would be best?
I want to use MVC basic functionality of using things like Html.ActionLink(action, controller, linkText) or make my own extension like Html.ActionLink(itemType, linkText) to make it even more flexible, so Action link should create correct routes based on Route data (because that's what's going on in the background - it goes through routes top down and see which one returns a resulting URL).
I was thinking of having a configuration of relation between itemType and route values (controller, action, defaults). Defaults setting may be tricky since defaults should be deserialized from a configuration string into an object (that may as well be complex). So I thought of maybe even having a configurable relation between itemType and class type that implements a certain interface like written in the example below.
My routes can be changed (or some new ones added) in the data store. But new types should not be added. Configuration would provide these scenarios, because they would link types with route defaults.
Example:
Interface definition:
public interface IRouteDefaults
{
object GetRouteDefaults();
}
Interface implementation example:
public class DefaultType : IRouteDefaults
{
public object GetRouteDefaults()
{
return new {
controller = "Default",
action = "Show",
itemComplex = new Person {
Name = "John Doe",
IsAdmin = true
}
}
}
Configuration example:
<customRoutes>
<route name="Cars" type="TypeEnum.Car" defaults="MyApp.Routing.Defaults.Car, MyApp.Routing" />
<route name="Fruits" type="TypeEnum.Fruit" defaults="MyApp.Routing.Defaults.Fruit, MyApp.Routing" />
<route name="Shoes" type="TypeEnum.Shoe" defaults="MyApp.Routing.Defaults.Shoe, MyApp.Routing" />
...
<route name="Others" type="TypeEnum.Other" defaults="MyApp.Routing.Defaults.DefaultType, MyApp.Routing" />
</customRoutes>
To address performance hit I can cache my items and work with in-memory data and avoid accessing the database on each request. These items tend to not change too often. I could cache them for like 60 minutes without degrading application experience.
There is no significant performance issue if you define a complex routing dictionary, or just have one generic routing entry and handle all the cases yourself. Code is code
Even if your data types are not inheritable, most likely you have common display patterns. e.g.
List of titles and summary text
item display, with title, image, description
etc
If you can breakdown your site into a finite number of display patterns, then you only need to make those finite controllers and views
You them provide a services layer which is selected by the routing parameter than uses a data transfer object (DTO) pattern to take the case data and move it into the standard data structure for the view
The general concept you mention is not at all uncommon and there are a few things to consider:
The moment I hear about URL routing taking a dependency on data coming from a database, the first thing I think about is performance. One way to alleviate potentialy performance concerns is to use the built in Route class and have a very generic pattern, such as "somethingStatic/{*everythingElse}". This way if the URL doesn't start with "somethingStatic" it will immediately fail to match and routing will continue to the next route. Then you'll get all the interesting data as the catch-all "everythingElse" parameter.
You can then associate this route with a custom route handler that derives from MvcRouteHandler and overrides GetHttpHandler to go to the database, make sense of the "everythingElse" value, and perhaps dynamically determine which controller and action should be used to handle this request. You can get/set the routing values by accessing requestContext.RouteData.Values.
Whether to use one controller and one action or many of one or many of each is a discussion unto itself. The question boils down to how many different types of data do you have? Are they mostly similar (they're all books, but some are hardcover and some are softcover)? Completely different (some are cars, some are books, and some are houses)? The answer to this should be the same answer you'd have if this were a computer programming class and you had to decide from an OOP perspective whether they all have a base class and their own derives types, or whether they could be easily represented by one common type. If they're all different types then I'd recommend different controllers - especially if each requires a distinct set of actions. For example, for a house you might want to see an inspection report. But for a book you might want to preview the first five pages and read a book review. These items have nothing in common: The actions for one would never be used for the other.
The problem described in #3 can also occur in reverse, though: What if you have 1,000 different object types? Do you want 1,000 different controllers? Without having any more information, I'd say for this scenario 1,000 controllers is a bit too much.
Hopefully these thoughts help guide you to the right solution. If you can provide more information about some of the specific scenarios you have (such as what kind of objects these are and what actions can apply to them) then the answer can be refined as well.

Resources