In three.js I've created a basic 'hero creation' program. Similar to Elder Scrolls swapping through heads,body etc to create a full character. I'd like to make it more interactive by letting other users edit the same hero. Each user will just read the same JSON file off the server.
To structure my code better I want to use MVC pattern but I'm confused about how to apply it.
I think all my event listeners will be a controller but would the View just be my three.js render() and the Model just the underlying JSON? Specifically applying MVC to this graphics domain is my big problem. If this is very bad form, would you have any suggestions on a different pattern/way to structure?
The View layer should:
Contain the rendering logic
Process user input and forward it to the controller layer (using the strategy pattern)
Keep your three.js objects in sync with the models
The Controller layer should:
Process the user input and update the models
The Models are your main entities. They shouldn't have any three.js related functionality.
I wrote a blog post that explains how to combine MVC and Three.js in detail: http://hecodes.com/2016/07/using-mvc-pattern-for-building-complex-three-js-applications/ .
You might find it helpful.
You may use a combination of MVC and Bridge pattern.
In this combination, you may abstract your view and use bridge pattern to allow your view to be created in several different formats.
Following link might help you : http://www.oodesign.com/bridge-pattern.html
To understand easily, you may consider this:
var modelObject = {};
var viewObject = {};
var controllerObject = {};
modelObject.str = "Welcome";
viewObject.showStr = function(modelObject) {
console.log(modelObject.str);
}
controllerObject.handler = function() {
viewObject.showStr(modelObject);
}
You can now call the function by handler while onclick or any event etc.,
Usually model is an abstraction of a data/data source
Related
I'm trying to get a practical grasp of MVC model implementation (not the conceptual understanding) in JavaScript.
As for the start, I thought it would be worth making an effort and try building a MVC app in plain JS. I've read dozens of articles and book chapters referring to MVC and its variations. Of course I googled lots of examples to see how it's done for real. The most understandable and with the proper meaning is in my opinion this one:
https://github.com/tastejs/todomvc/tree/master/examples/vanillajs
In the end, I was able to refactor my own app in the todomvc-vanillajs way.
However, there is one thing that still bothers me. All these apps and examples are very basic, so there is only one Model, View and Controller specified for the whole app.
What if I wanted to add more (equally complex) features to such app?
Should I add them one by one to my controller.js view.js and model.js files or whether should I stop developing spaghetti code and add new files instead, thus creating new models, controllers and views for each of the new feature individually?
It seems to me, that every feature should have its own view, controller and model, or at least, could have, depending on the subjective evaluation. But I'm not quite sure how such implementation should look at this situation in terms of code structure, namespacing etc.?
What if I want to imitate a scale by creating multiple views, models and controllers on every single functionality like e.g. handling an "add task to the list" or "delete the task" actions.
For the purpose of my dilemma, I've created my own MVC draft, which has two models, controllers and views. Whether such an approach would make sense? What happens when further developing my application, I quickly get to the point where I have dozens and more specific (coresponding) models, views and controllers.
Heres is the aforementioned fiddle.
;(function () {
'use strict';
/**
* #file ./App.js
*/
var App = {
Model : {},
Controller : {},
View : {}
};
console.log('start');
window.App = App;
})();
/* -------------Views-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildAdd.js
*/
var buildAdd = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildAdd = buildAdd;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildDelete.js
*/
var buildDelete = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildDelete = buildDelete;
})(App);
/* -------------Controllers-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.addController = addController;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.deleteController = deleteController;
})(App);
/* -------------Models-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addModel = {
// send request
// get response
};
App.Model.addModel = addModel;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteModel = {
// send request
// get response
};
App.Model.deleteModel = deleteModel;
})(App);
/* -------------separate-file-----------------------*/
Thus, I found this question very similar to mine, but the provided answers are not entirely satisfactory, at least to me.
Check my implementation of so called Single Page Application framework. The whole thing is of 60 lines of code. It uses jQuery but can be implemented in VanilaJS.
Basic idea is simple - your app is just a collection of pages a.k.a. views
<section id="route1" src="content1.htm" />
<section id="route2" src="content2.htm" />
...
Sections id's define set of possible "routes"
SpAPP catches browser's navigate event and load requested view on the route.
And partial content1..N.htm files contain view markup, setup and controller functions.
Data model here is JS data received from server and stored in memory or in local storage.
As of MVC frameworks in general... You cannot bring joy to everyone and free of charge. That small SpAPP thing that can easily be understood and adjusted to particular project's needs is a way to go I think.
Looking at my experience in Ruby on Rails framework, I don't always need all three elements of MVC pattern. Sometimes you need a model for a database but it's only accessed internally, not by the client. Or sometimes you only need a generic helper class.
As a convention, the files are split, each one has its own controller, model and view, following a naming convention, maybe something like:
articles-view.html
articles-controller.js
articles-model.js
Views are split for each action in the controller:
articles-index.html
articles-show.html
articles-update.html
...
articles-controller.js
articles-model.js
Inside the controller, you will have the "actions", the functions for everything semantically related to an Article in a blog.
function ArticlesController() {
function index() { ... }
function create() { ... }
function edit() { ... }
...
function delete() { ... }
}
In models, you basically have the class / prototype itself, something that is built with the given data.
function Article() {
this.name = "";
this.author = "";
this.text = "";
this.dateCreated = "";
}
And finally, your views should have element with the same name used in the model.
If you have a basic CRUD system, for example, you can have just one controller and one model, but different views (one for listing all items, one for creating and editing, one for just one item, etc).
Taking examples from Rails and NodeJS, a way to write less code for the views is by using "partials". Common HTML structures can be saved on a file and imported into other HTML files as needed, such a form, the headers, the footer of a page and so on.
Example:
Instead of having a form on articles-create.html and another on articles-edit.html, you will have something like:
_articles-form.html <- this is your partial!
articles-create.html
articles-edit.html
"_articles-form.html" will be imported / appended into the create and edit pages.
Other common features can be consider as "Helpers". They are not a letter in "MVC", but often used. Like the Datepicker library, a simple validation function, a parser, etc. Something that can be used by everyone, not a specific feature of a class.
The project structure could be something like:
app/
app/controllers/
app/controllers/articles-controller.js
app/models/
app/models/articles-model.js
app/views/
app/views/articles/
app/views/articles/index.html
app/views/articles/create.html
app/views/articles/edit.html
app/views/articles/delete.html
app/views/articles/_form.html
Also, having a Manager functionality as you described above, will help you load all the data needed. Some function that maybe will read a json file, looking for the feature's name and parsing through the file's names, loading everything.
The manager would check if there is a model file, a controller file and a folder with N view files in it, containg the word "articles". The same would happen to "authors", "comments", "users" and so on.
I understand that you are proposing this question for study reasons and you took JS as a personal preference, so I´m not saying "don't try it" or something like that. But something to consider: the MVC pattern tackles applications that involves both client and server side. Unless your are developing on a full stack with NodeJS and MongoDB (or other similar technologies), HTML and Javascript are more on the View side of the application (or as helpers).
And if you are developing something like a library, you'll end up putting everything on a single file and minifying/uglifying it. Take JQuery as an example. Javascript developers often go with the Module pattern. They create an object, expose methods and variables that the other developer needs to know and that's it.
So, probably (but not for sure, you never know!), you won't see or work on many vanilla Javascript applications implementing MVC pattern.
I have implemented a single page application with AngularJS. The page consists of a content area in the middle and sections assembled around the center that show additional info and provide means to manipulate the center.
Each section (called Side Info) and the content area have a separate AngularJS controller assigned to them. Currently, I communicate via $rootScope.$broadcast and $scope.$on(), e.g.
app.controller('PropertiesController', function ($scope, $rootScope) {
$scope.$on('somethingHappened', function(event, data){
// react
});
});
I then call to communicate with other controllers:
$rootScope.$broadcast('somethingHappened', data);
I have quite a lot of communication happening between the Controllers. Especially if something is going on in the content area, several side info elements have to adopt. The other way around is also frequent: a user submits a form (located in a side info) and the content area and other side info elements have to adopt.
My question:
Is there a better way to handle SPA with heavy controller communication?
The code works fine but it is already getting a bit messy (e.g. it is hard to find which events are handled where etc.). Since the application is likely to grow a lot in the next weeks, I'd like to make those changes (if there are any better solutions) asap.
This is really interesting. Pub/Sub should be a right solution here.
You could add extra order to your project by using Angular services as your MVC's model, and update this model for each change. The issue here is that you should implement an observable pattern inside your service and register to them, in order for this to be live synced. So - we're back to Pub/Sub (or other Observable solution that you could think about...).
But, the project will be better organised that way.
For example - SideInfo1Service will be a service/model. Each property change will trigger an observable change which will change all listeners:
myApp.factory('SideInfo1Service', function($scope){
var _prop1;
return {
setProp1: function(value){
$scope.$broadcast('prop1Changed', value);
_prop1 = value;
},
getProp1: function(){
return _prop1;
}
}
});
You could find those really interesting blog posts about using Angular Services as your MVC's model:
http://toddmotto.com/rethinking-angular-js-controllers/
http://jonathancreamer.com/the-state-of-angularjs-controllers/
And, this post is about observable pattern in Angularjs:
https://stackoverflow.com/a/25613550/916450
Hope this could be helpful (:
You have multiple options in order to avoid broadcasts calls:
Share data between controllers using services like it was mentioned in the comments. You can see how to this at: https://thinkster.io/egghead/sharing-data-between-controllers
Create a main controller for the whole page and child controllers for each section (Content Area and Side Info). Use scope prototype inheritance. For example:
if in main controller you have:
$scope.myObject = someValue;
in child Controllers you can set:
$scope.myObject.myProperty = someOtherValue;
you can access myObject.myProperty from your Main Controller
You can use
$rootScope.$emit('some:event') ;
because it goes upwards and rootscope ist the top level
use
var myListener = $rootScope.$on('some:event', function (event, data) { });
$scope.$on('$destroy', myListener);
to catch the event
Then you have a communication on the same level the rootscope without bubbling
Here is my implemented eventbus service
http://jsfiddle.net/navqtaoj/2/
Edit: you can use a namespace like some:event to group and organize your event names better and add log outputs when the event is fired and when the event is catch so that you easy can figure out if fireing or catching the wrong eventname.
Very important question and very good answers.
I got inspired and created three plunks showing each technique:
Broadcasting: http://embed.plnkr.co/lwSNDCsw4gjLHXDhUs2R/preview
Sharing Service: http://embed.plnkr.co/GptJf2cchAYmoOb2wjRx/preview
Nested Scopes: http://embed.plnkr.co/Bct0Qwz9EziQkHemYACk/preview
Check out the plunks, hope this helps.
It may be a very dumb question... I am using Meteor-ui-progress-circle and I want redrawing the template when the percentage (wich is store in a reactive collection Progress) is changed (currently, when I click on a "play" button).
I think I have to use Blaze.render but I don't really understand how it work.
Here a part of my main template (in Jade) :
div.panel-body
div.col-md-9.col-sm-8
p Lorem ipsum...
div.col-md-3.col-sm-4#progress-circle
+progressCircle progress="0" radius="100" class="green"
And my JavaScript :
Template.controlBar.events(
{
"click .play-button": function ()
{
var tmp = Progress.findOne({});
if (!tmp)
{
Meteor.call('createProgress');
tmp = Progress.findOne({});
}
var val = tmp.progressValue;
val += 10;
if (val > 100)
return;
Meteor.call('updateProgess', tmp._id, val);
Template.progressCircle.progress = tmp.progressValue;
Blaze.render(Template.progressCircle, $("#progress-circle")[0]);
},
Doing this... I have several template that are displaying each time I click on the play button. I don't understand how to specify that I don't want a new template but just re-render the one I already have.
Not sure I quite understand your question, but I'll try to help by giving my best understanding of templating and how I have come to use them. If someone sees any incorrect information here, please speak up so I can get a better understanding myself and correct this answer.
First, the Template.XXX.events handlers. In your event handler, you are using a function with no arguments. You can actually accept 2 arguments for these event handler functions: the event and the template. So, you can do something like thus:
Template.controlBar.events({
'click .play_button': function(event, tmpl) {
tmpl.$('div#progress-circle').doSomething();
}
});
Notice the tmpl.$() call? That says to use jQuery to find the specified selector, but ONLY in the current template. This is a wonderful way to use classes to generalize your components, but then be able to filter the selection to only those within the same template...
...Which brings me to my next bit of advice: Use child templates excessively. Any component that I can identify as an "autonomous component" on my page I will consider as a separate template. For instance, I was recently working on a custom reporting page that had a table and some D3 graphs representing some real-time data. In this report page, I had one main template defined for the "page", then each of the D3 graphs where defined as a separate template, and the table was another separate template. This allows several advantages:
Compartmentalization of the "components" of the page, allowing code reuse (I can now put the same graph on ANY page, since it's now an autonomous "component"
The advantage of using the Template.XXX.events trick above to "narrow" the scope of my element searches to elements within that template
Prevents total page refreshes as Meteor is smart enough to only refresh templates that need to be refreshed, which also speeds the responsiveness of the page itself
As a result, I try to apply my Templates liberally. In your case, it would sound to me that if I were to have multiply progress bars on the page that I might turn those into separate templates. I might even do it if I had a single progress bar if it made sense to separate it out for ease of data handling.
Finally, inter-communications between Templates. This can be tricky at times, but the best, most efficient way to do this I have found is through Session variables. The pattern I typically use is to have my data for my template be returned by a Template .helper, which does something like this:
Template.controlBar.helpers({
progressData: function() {
if (!Session.equals('playId', null)) {
return Progress.findOne({_play_id: Session.get('playId')});
}
}
});
Because Helpers are reactive, and Sessions is reactive, the template is re-rendered anytime the 'playId' is altered in the Session. The corresponding Session variable can be set from anywhere in the client code. Again, this tends to work best when you narrow the scope of your templates to the individual components. It is important to note here that the Session object in Meteor is NOT the same as "sessions" in other languages like Java and such, which typically use cookies and a session token/id. Meteor sessions work considerably different, and do not survive page reloads or closing of browsers.
I am designing a generic object browser plugin which functions similar to OS X's Finder in column view. I have divided up the interface in to several nested views, the browser, the columns and the objects.
I will be using this plugin in several scenarios where the browser view, object view and column view may or may not need to be customised. Sometimes the objects will be files and folders for example.
This is OS X's Finder in column view in case you don't know what it looks like.
At the moment I am using RequireJS to pass around the dependencies however in order to simply inherit and extend the ObjectView, I must replace the entire stack.
Is there any better structure where the plugin can be extended but only part of?
BrowserView.js
var BrowserView = Backbone.View.extend({
open: function () {
var collectionView = new CollectionView( {collection: objects} );
}
});
CollectionView.js
var CollectionView = Backbone.View.extend({
render: function () {
this.collection.each( function (object) {
var objectView = new ObjectView( {model: objects} );
objectView.bind('click', this.select, this);
this.container.append( objectView.el );
objectView.render();
this.objectViews.push(objectView);
}, this );
},
});
ObjectView.js
var ObjectView = Backbone.View.extend({
});
I would put these views in the same module.
The purpose of a module - whether you're using RequireJS or just plain old JavaScript modules - is to encapsulate a set of related objects and functions, for a specific purpose. In this case, your purpose is the Finder View.
By keeping all of the related objects in the same file, you'll have more freedom and flexibility for how you make the objects work together.
As a side note, but related to what you're doing, you might be able to get some ideas for how to make this work from the "CompositeView" of my Backbone.Marionette plugin. I've built a hierarchical tree-view of folders and files with it before, and the column view of Finder would be fairly easy to build with it, too.
Note that I'm not suggesting you need to use my plugin. Rather, I think it might be helpful in figuring out how you want to structure your code.
I've got a blog post that talks about it here: http://lostechies.com/derickbailey/2012/04/05/composite-views-tree-structures-tables-and-more/
You can find the code and docs here: https://github.com/derickbailey/backbone.marionette
And the annotated source code for the composite view is here: http://derickbailey.github.com/backbone.marionette/docs/backbone.marionette.html#section-26
I'm trying to figure out if Backbone.js is the right framework for my current project: a visualization app.
I have a number of questions:
1) State / Routing?
As this is not your typical RESTful app, but rather a visualization application with various chart types and settings for these charts, how do i maintain state in the URL?
Let's say my areaChart model has a number of defaults like this:
AreaChartModel = Backbone.Model.extend({
defaults: {
selectedCountries: [],
year: 1970,
stacked: false
},
initialize: function(){
[...]
}
});
On an update to the model I'd like to serialize some of these attributes so that I can bookmark the specific state: chartApp.html#!year=1970&stacked=false etc.
And vice-versa, when initing the app with this state, how do I "deparam" the url state and set the model? Can I use Backbone's intrinsic routing?
2) Controller and coupling?
It seems as Backbone has a pretty tight view-model coupling?
Is this really how I should bind for example my areaChartView to the model?
AreaChartView = Backbone.View.extend({
initialize: function(){
areaChartModel.bind("change:year", this.render);
}
});
Isn't this normally the role of the controller?
3) Continuation: Model vs. Controller?
Given this scenario:
A change in the "Sidebar" should trigger a sequence of functions:
1) "New data for the current selection should be loaded"
2) "Based on this data, the scales in the Visualization view should be updated"
3) "The visualization view should be rendered"
Where should I place these functions and how can I create an event in the model that I trigger when the state is stable? (i.e. when all the functions have been invoked and it's time to set the view states?)
1) I would use Backbone.js native routing as much as possible using “:params” and “*splats” , read more. You could fit all your queries into the Backbone.js routing but I would personally sacrifice certain things in favor of intuitive UI buttons
e.g. I would have the default as a line bar and you can't preset this with the URL but to change to a stacked graph would be a simple click of a button.
I would probably stray from ever using ? and & in my URL's. I might come back to this point later as it is interesting.
2) Your example is fine and you just need to remember Backbone.js MVC terminology doesn't correlate to traditional MVC.
Backbone Views are essentially the Controller in traditional MVC.
Backbone Controllers are simply a way of routing inside a framework.
The templating engine you use with Backbone.js is the traditional MVC view.
3) Still writing
Regarding question #3, I would create a Model and a View for the slider.
Then I would associate the triggering of the change event on the model to some function in the view that updates the graph's view (like changing the scales). Something like:
var Slider = Backbone.Model.extend({})
var SliderView = Backbone.View.extend({
initialize: function() {
this.model.bind('change', this.render);
}
render: function() {
// load data, change scales, etc.
}
});
var slider = new Slider();
var slider_view = new SliderView({ model: slider });
Maybe a good idea would be to put the bindings in a parent view, that would then dispatch to sub-views, coordinating their work.
Do sit down for a while and consider if maintaining the entire state is at all a good idea ? The key motivations for having url-based state management is being able to support browser based navigation buttons and being able to bookmark a page. In a visualization app, your data would probably change every moment. This is not something you want to persist in your app-url. Do you really want that when a user bookmarks your app and comes back to it three days later - he sees the visualization for three days old data ? For your scenario, assuming I have not misunderstood your requirements, I would recommend to keep the data state in your model itself.
Also regarding synchronization of views with model data, Yes you can code all the binding logic on your own. In that case your View class will take care of setting up the bindings on the first render. And upon subsequent calls to render, which can be invoked in response to any change event in the model, will refresh the DOM/canvas where the visualization is present.
Probably you should be look forward to a plugin for data-synchronization that takes care of much of boilerplate for you. This page lists some of the data-binding extensions available. Orchestrator is another solution that I have been working on, which might be helpful in this regard.