The problem.
I have a set of modules that need to share the same collections.
The collections need to be ready before the modules are started.
I'm not sure how to solve this in the cleanest way, and i realize that this might vary from project to project, but here is some thoughts.
Loading the collections before start up.
This is the first thing that comes to my mind, simply load the collection
just before i call the "App.start()".
Then I can just make it accessible in the global scope (not sure i like this.).
Delaying sub-modules start-up until load.
If I structure the app so it has a main module, that is responsible for starting up all sub modules.
Then I could pre-load all vital data, and make sure it was ready, before starting any sub modules.
Then maybe make it accessible through the main modules API.
I don't know if this is poor design, sins my experience with marionette is limited.
How I'm doing it now.
Atm I have choose to load the collections before "App.start()", this made sens sins
I'm also pre-loading my templates.
I have introduced a 'static' object called 'CollectionManager', that acts as a proxy/Access point for my collections. And will be globally available.
Application setup:
// Templates that should be ready on start up
var arrTemplatesPaths = [...];
// Collections that i need to be ready and shared between modules.
var arrSharedCollections = [
{id:"groups", collection: GroupCollection}
];
// Preloading the vital data.
$.when.apply(null, [
Templates.fetch(arrTemplatesPaths),
CollectionManager.fetch(arrSharedCollections)
])
.then(function(){
App.start();
})
Access:
Then the modules that need access to the collection can just call
CollectionManager.get( id )
var collection = CollectionManager.get("groups"); //#return Backbone.Collection
This provide some structure, but im not sure i like it all that much.
Update
So after digging a little in the Marionette doc i noticed the Marionette.RequestResponse.
That provides a clean way to request data from within modules, creating a
level of abstractions over my approach, that coupled things in a annoying way.
So I have added this line to the application:
App.reqres.addHandler("getCollection", function (id) {
return CollectionManager.get(id);
})
Then from within the modules i access the collections this way:
var collection = App.request("getCollection", "groups")
I like this way more then accessing the CollectionManager directly from within the modules.
On the topic of loading Collections/Models before or after showing Views, I have found that the best approach is to fetch the Model/Collection in a Marionette Controller, then show the View, passing in the model/collection once it has been fetched. Looks like this:
Controller (or Router)
showUser: function(id) {
var userModel = new UserModel({id: id});
userModel.fetch().then(function() {
mainRegion.show(new UserView({model: userModel}));
});
}
Related
I'd like to get the path to a package public directory (css etc) based on the package alias.
Is there anything already built into the laravel framework?
In other words something like:
public_path('myalias');
When I'm talking about alias, you would typically "alias" a module by adding the following within your service provider's boot method:
$this->package('namespace/package','alias_name');
For those wondering why someone might want to do this:
We are running a multi domain/subdomain application that makes use of a central piece of code for all of the domains and then specific packages per domain (I'll refer to them as funnels).
Each funnel has its own controllers that can possibly extend base controllers to implement their own functionality while re-using code where they can. They also have their own views.
The funnel refers to its own views by way of something like:
View::make('funnel::path.to.view')
The way we accomplish this is by doing some business logic on page load to only load the FunnelServiceProvider related to that particular domain and aliasing it to "funnel". This way our base controllers can also refer to funnel and not be tied to a particular packages views,includes,blocks etc.
My hope is to do something similar on the views so that I can simply call something like get_funnel_path() to get the path to the funnel that is currently being loaded.
The value could then be used to load css,js,images etc without worrying about the funnel path.
This would allow us to simply copy and paste views from one domain to the next without having to modify all of the paths in potentially multiple files. We could also make use of globally included files in all/most of the views.
An example of this might be the head. The head section should be the same for 99% of the files, however the path where it loads its resources should change based on the funnel.
We use the same naming conventions for css files as well as use sass, imports, merging for all of the funnels; so only the path needs to change.
You can do something like this although it will only work with your own packages and require a bit of work. Because the alias is not really stored somewhere you can easily access you have to do that yourself.
First create some kind of class to store your package names in. I called mine PackageManager:
class PackageManager {
private $packages = array();
public function addPackage($fullName, $alias){
$this->packages[$alias] = $fullName;
return $this;
}
public function getPublicPath($alias){
if(!isset($this->packages[$alias])) return public_path();
$path = 'packages/' . $this->packages[$alias];
return public_path($path);
}
}
Now let's register that class as a singleton in a service provider:
$this->app->singleton('packagemanager', function(){
return new PackageManager();
});
Then, in every package you want to register, add this call in the boot method right next to $this->package():
$this->app['packagemanager']->addPackage('vendor/package', 'alias');
After that you can do this anywhere in your application:
app('packagemanager')->getPublicPath('alias');
If you want a shorter syntax, add this helper function somewhere:
function public_package_path($alias){
return app('packagemanager')->getPublicPath($alias);
}
And just do:
public_package_path('alias');
Using Durandal, I have two view models within my app, let's say vmCompanies & vmEmployees. I have two views, one for each view model and within each, you can see all companies & all employees.
However, when I'm loading my employees, in the DB they have an ID for which company they are employed by. What I'd like to do is the following pseudo:
From within the vmEmployees, get a reference to the vmCompanies
If the vmCompanies has already been initialized (which I know it is 99% of the time), get a reference to it so I can use something like linq.js to find the specific company this employee works for
If the vmCompanies has not been initialized (aka: activated), do so
This way I can avoid the requirement of the vmEmployees having it's own internal cache of companies. So far I've been unable to figure out how in Durandal to query and ask "give me this view model that you've already loaded." It seems like it has that internally because when I navigate between views, they are cached and not reloaded (same with the VMs)... I've just so far been unable to see how I can do it.
You can manually require() a view model by its ____moduleId____. As long as your view model module returns an object and not a function, you'll be dealing with a singleton, so you can be sure you'll get the correct instance.
If you're not sure what the __moduleId__ is, you can use this chrome extension to view your view model's properties, including __moduleId__.
However, instead of manually instantianting VMs, a better alternative may be to create a separate module that you use to store the cached companies. I have a data module with its own internal cache that I use generically for this purpose, but you could create one specifically for companies, and store that information in it. It could even be responsible for loading its own data, if that's appropriate.
Here's some simple code to help explain:
Note this uses the sugar syntax for require JS - if you're using the array-based syntax, you'll need to translate accordingly. I can help if needed.
//companies-cache.js
define(function(require){
//some auto-loading logic here, if you wish
var companies = ko.observableArray([]);
return {
companies: companies
};
});
//vmCompanies, vmEmployees
define(function(require){
var companiesCache = require("viewModels/companies-cache");
//additional properties for this specific VM
...
return {
companies: companiesCache.companies
};
});
I would like to "simulate" global variables in Angular. I would also like to be able to initialize those "global variables" in an App_Init()-type of handler. Such an initialization will require $http calls to populate those variables. I want all of the "global variables" to be completely loaded before Angular "calls up" controllers and views, because controllers would depend on the initialized data.
What are some best practices for that in Angular? Nested controllers? Services?
Example: An app that manages items in a restaurant's menu. Each item will be associated with a category (beverage, appetizer, dessert, etc.). I need to load all of those categories first before Angular "even touches" the controllers and views for the food items.
Are you using ng-view and the $routeProvider service for your app? Assuming you are or will consider, here is what you can do in order of steps:
Build a service that provides acces to the categories to its called. My idea is that this service would load the categories from the server when it's first called and then cache the data loaded, so the next time it's called a cache copy is served, instead, to save a request to the server. Let's call this service categories for now.
Use the resolve property of route object to ensure the dependency on the categories service is resolved before loading the view the user is requesting (and the corresponding controller). As a result, you can inject the categories service into the controller and be sure the service is always available because it has already been resolved.
If you have never worked with the resolve property in configuring routing before, Here is an example and the part of the official docs that talks about it. I recommend you go through them.
Also, in order to understand how resolve works, you need to be familiar with the concept of promise and deferred. If you are not, here is a good starting point on the topic. $q is AngularJS's implementation of promise/deferred.
I can't comment on if the above approach is the best practice, but I know it's a good practice to use service to provide access to some data/functions like if there were global variables.
You can create a service to load the configuration from server and put it in rootScope, in your controller you can call this service on your function and this function you call from ng-init in your view.
View
<mytag ng-init="myFunc()">
Controller
module.controller('MyCtrl', function($scope, myService){
$scope.myFunc = function(){
myService();
}
}
your service (initialize app)
module.service('myService', function($http, $rootScope){
//do something
$rootScope.config = configLoaded;
}
another tip
if you are in trouble with asynchronous calls you can try to use
var deferred = $q.defer();
//when your call come back
deferred.resolve(yourData);
//and in the last line of function
deferred.promise;
I have a menu which I need to create dynamically (some blog pages are added from a database). ZF2 Dynamic Menu with Zend\Navigation\Navigation addresses how to do this for an individual controller/action.
But how should this be done for all requests, at the moment of initialising the module?
I need at least the routeMatch object (to get the language parameter) and I have seen the below to get that:
public function onBootstrap(EventInterface $e)
{
$app = $e->getApplication();
$em = $app->getEventManager();
$em->attach(MvcEvent::EVENT_ROUTE, function($e) {
$routeMatch = $e->getRouteMatch();
});
}
But in the docs it says:
"the onBootstrap() method is called for every module implementing this feature, on every page request, and should only be used for performing lightweight tasks such as registering event listeners."
What would be the best place and way to initialise dynamic navigation (or other more complicated logic) in Zend Framework 2?
The correct place is indeed bootstrap to do this sort of things. Bear in mind the code at bootstrap is run at every request, so make it as lightweight as possible. If you want to inject navigation, try to cache the navigation structure from your database and inject the version from cache.
This behaviour is something I did in ensemble. It fetches data from the database to build routes dynamically and based on the routes, the navigation structure is build. The routes and navigation are injected in respectively the router and navigation container, so at dispatch of the application is seems there is nothing different from a "normal" request with routes configured in the module.config.php.
For some examples you should check out the kernel, currently only availble with a Doctrine adapter (Zend\Db coming soon). It registers listeners to hook up early, it parses the database results into a route and navigation structure and those can be cached to increase performance.
If you need more specific information, please update your question to ask more about what you miss in the bigger picture.
I'm looking to try, for the first time, a JavaScript MVC framework like Knockout, Backbone.js, Spine, JavaScriptMVC, etc.
I've started looking at some of the documentation available for these frameworks and I'm having trouble finding examples of how they handle relational data. Most of them use a ToDo list as an example. A ToDo list is nice, but it doesn't cover relational data. Perhaps a better example would be a cookbook with a model for both recipes and ingredients:
var Recipe = function(){
this.name = "Pizza";
this.description = "A delicious baked, flat, disc-shaped bread topped with tomato sauce and cheese.";
}
var Ingredient = function(){
this.name = "Tomato sauce"
}
var IngredientToRecipe = function(){
this.recipe = null;
this.ingredient = null;
this.quantity;
}
The examples for models that I've seen so far do not seem to deal with the problems of relationships: foreign keys, id generation, etc. The example above is a many-to-many relationship, but I would be happy with support even for one-to-many relationships.
I really like the things provided by these frameworks:
changes to the models automatically update the view (i.e. DOM)
automatically updating the model on the server when it changes
clear organization of code
etc...
But, I'd like advice on which framework best handles relationships between models and has an example where that is done.
Thanks!
While Backbone (intentionally) doesn't support models containing other models/collections very gracefully, Backbone-relational adds support for it and works quite well. Check out their documentation.
Sproutcore has a client side datastore which allows you to relate different model object to each other in toOne, toMany, and ManyToMany relationships. You can actually write queries against the store which automagically update when the data changes. Similarly, if you do an update and a model object changes, any views attached to that model (via a controller) will automatically update). Also, SC has a nested store functionality which allows you to abandon changes seamlessly, for the 'save or cancel' type workflows.
http://guides.sproutcore.com/records.html
I don't think you're looking for MVC per se, I think you're looking for something with a good "M". So you might be looking for something like our Ext JS model associations. (Ext JS is of course, a full on framework, so if you're looking to sprinkle something on top of jQuery, it won't be for you.)
Here is the documentation for models in Ext JS 4 and here is the top level guide for Ext JS 4 MVC