I'm new in Highcharts.js and Marionette.js ,
Task:
I try to create two Marionette app's such that each of them would store a Highcharts.Chart() , such that both of these two Chart()'s would be appeared each time on the same region .
Implementation:
So my general idea is like that -
Let's Graph1Manager be the 1st Marionette app -
var Graph1Manager = new Marionette.Application()
and main-region the region for the Charts()'s -
<div id="main-region" class="container"> Here would be a chart </div>
For Graph1Manager I implemented the -
Graph1Manager.on("initialize:after", function () {...})
such that Graph1Manager loads all the data required for the 1st Chart() once .
So my question is:
Where and how I have to store and draw the Chart() on Graph1Manager ?
Does it have to be in any Marionette.ItemView.extend ?
I have previously built an application using Marionette and Highcharts so I think I can speak to this from some experience.
There's more than one way to go about this but in general unless you have some special reason you would just want to have one Marionette app running. I can't tell if you're trying to display two views at the same time in the same region but in case you are this is definitely not possible--as soon as you show the second view the first will be removed from the dom.
Anyways on to your questions:
The simplest way (and the way I have done this) is to use an ItemView and draw the chart in the onRender() method. So it will look something like this:
var MyView = Marionette.ItemView.extend({
template: _.template('<div class="chart-container" style="height: 325px;"></div>'),
onRender: function() {
this.$('.chart-container').highcharts({
...highcharts options here
})
}
});
Then when you're ready to display it you'll create an instance and show it in the region:
var view = new MyView();
Graph1Manager.nameOfRegion.show(view);
Whenever you show another view in the region the previous one will automatically close so remember you'll have to create a new instance of it if you want to use it again...
Related
I'm looking for a better equivalent of:
if (view.myRegion.currentView) {
view.myRegion.reset();
} else {
var myOtherView = new Marionette.ItemView();
view.myRegion.show(myOtherView);
}
I went through the docs, but didn't find anything similar unfortunately.
From the docs - showing a view on marionette site, under the preventDestroy section,
If you replace the current view with a new view by calling show,
by default it will automatically destroy the previous view.
So perhaps, this could be helpful to you. Region manager would automatically destroy the existing view which is being held by that region and then render the new one.
If there's anything specific that you would like to do at the time of destroy, I believe you can write onDestroy callback for that view.
In the SAPUI5 / OpenUI5 xmlfragment documentation the third parameter is a controller for handling actions from the fragment.
This is critical for a dialog fragment where there are buttons to press etc.
Most of the time I have seen this instantiated as this or sap.ui.getCore().byId('<element>').getController())
See an example at Fragment not get correct Controller
Because of the complexity in a particular dialog I would like to have a separate controller for it.
I have looked around at this and had a few attempts but so far not successful.
I have put a working example on github of using this.
But I would like to instantiate Dialog.js as the controller for the Dialog.fragment.xml from initial.view.controller
Any takers?
Pull requests gladly received.
The Crux of the example is as follows (this is the initial.controller.js) :
sap.ui.controller("sc.test.view.initial", {
oDialog: null,
openTestDialog: function(){
console.log("in open dialog");
// instantiate the other controller
var oDialogController = new sc.test.view.Dialog();
// this next commented line is the 'normal' way to do it
// oDialog = new sap.ui.xmlfragment( "sc.test.view.Dialog", this); //oDialogController);
// this is what I would like to achieve
oDialog = new sap.ui.xmlfragment( "sc.test.view.Dialog", oDialogController);
oDialog.open();
},
onCartDialogCancel:function(oEvent){
// this function would then be in the other controller but how to get a handle on the dialog?
oDialog.close();
}
});
Thanks.
(Just got to SYD airport)
All you're missing is the
jQuery.sap.require("sc.test.view.Dialog");
in your initial.controller.js.
Pushed a quick fix in a branch to your repo and opened a PR
only example i could find close to yours was in the Material Shortage Fiori app
oCtrl = sap.ui.controller("myapp.fragments.DirectCallDialog");
oDirectCallDialog = sap.ui.xmlfragment("myapp.fragments.DirectCallDialog", oCtrl);
lots of examples of injecting a controller when the fragment was called from a helper class. The helper class promotes reuse, eg same dialog fragment can be called from multiple views/components. The helper class method for the dialog setup is called from within a controller and the oController parameter is set to 'this'.
hth
jsp
I copied an existing controller.js, and renamed it.
Then, instantiated that as a below, and passed it through with the fragment.
var oNewController = new sap.ui.core.mvc.Controller("myProject.DialogController");
this._oDialog = sap.ui.xmlfragment("myPopup","myProject.fragments.myPopup", oNewController);
All eventing is now handled in oNewController, rather than the previously used "this"...
We are currently building a Marionette based application.
Basically, we have a Marionette Application that has multiple regions defined on it.
Each region will act as a container for different Modules to display their views. I want each Module to have full control of what is being displayed in it's container, but I want the Application to allocate these regions. For simplicity, let's say that each module just has a simple ItemView.
I'm considering 2 approaches to populating those regions with the module views.
The first approach says that when each module is initialized, it will create its view and it will call the application to display its view in the specified region, for example:
var app = new Marionette.Application();
app.addRegions({
regionA: "#regionA",
regionB: "#regionB"
});
app.module("moduleA", function(moduleA, app, ...){
moduleA.on("start", function(){
var viewA = new MyViewA();
app.regionA.show(viewA);
}
});
app.module("moduleB", function(moduleB, app, ...){
moduleB.on("start", function(){
var viewB = new MyViewB();
app.regionB.show(viewB);
}
});
The second approach says that each module should expose some function that returns its view. The Application will call that function when ready and it will stick the view in the designated region.
I'm not sure which approach is better and would be happy to hear opinions.
I would definitely go with the second approach, after having gone with the first approach in the past I am now hitting the limitations of this approach and moving to the second approach. I wrote a blog post about it here
It depends which approach you take, both are fine, we choose the second option because we use require.js to load our modules dynamically.
var dashboardPage = Backbone.Marionette.Layout.extend({
template: Handlebars.compile(tmpl),
regions: {
graphWidget : "#graphWidget",
datePickerWidget: "#datePickerWidget",
searchWidget : "#searchWidget"
},
widget: {
graphWidget: null,
datePickerWidget: null,
searchWidget: null,
},
initialize: function(options){
this.someId= options.someId;
//if have someId ID - fetch model;
if(this.someId){
//fetch model if campaignId not null
this.modelAjax = this.model.fetch();
}
onShow: function() {
var that = this;
if(this.modelAjax){
this.modelAjax.done(function(){
that.widget.graphWidget= new graphWidget(graphWidgetOptions);
that.listenTo(that.widget.graphWidget, 'graphWidget', that.getGraphWidgetData, that);
....
that.graphWidget.show(that.widget.graphWidget);
that.datePickerWidget.show(that.widget.datePickerWidget);
I'm trying to figure out following scenario:
Lets say that I have two views: one for viewing items and one for buying them. The catch is that buying view is a sub view for viewing.
For routing I have:
var MyRouter = Backbone.Router.extend({
routes: {
'item/:id': 'viewRoute',
'item/:id/buy': 'buyRoute'
}
});
var router = new MyRouter;
router.on("route:viewRoute", function() {
// initialize main view
App.mainview = new ViewItemView();
});
router.on("route:buyRoute", function() {
// initialize sub view
App.subview = new BuyItemView();
});
Now if user refreshes the page and buyRoute gets triggered but now there is no main view. What would be best solution to handle this?
I am supposed that the problem you are having right now is that you don't want to show some of the stuff inside ViewItem inside BuyView? If so then you should modularized what BuyView and ViewItem have in common into another View then initialize it on both of those routes.
Here is a code example from one of my apps
https://github.com/QuynhNguyen/Team-Collaboration/blob/master/app/scripts/routes/app-router.coffee
As you can see, I modularized out the sidebar since it can be shared among many views. I did that so that it can be reused and won't cause any conflicts.
You could just check for the existence of the main view and create/open it if it doesn't already exist.
I usually create (but don't open) the major views of my app on booting up the app, and then some kind of view manager for opening/closing. For small projects, I just attach my views to a views property of my app object, so that they are all in one place, accessible as views.mainView, views.anotherView, etc.
I also extend Backbone.View with two methods: open and close that not only appends/removes a view to/from the DOM but also sets an isOpen flag on the view.
With this, you can check to see if a needed view is already open, then open it if not, like so:
if (!app.views.mainView.isOpen) {
//
}
An optional addition would be to create a method on your app called clearViews that clears any open views, perhaps with the exception of names of views passed in as a parameter to clearViews. So if you have a navbar view that you don't want to clear out on some routes, you can just call app.clearViews('topNav') and all views except views.topNav will get closed.
check out this gist for the code for all of this: https://gist.github.com/4597606
I have an application that has a middle panel that always changes depending on what part of the application the user is looking at. These might be messages, transactions etc.
Then there are 4 'fixed' panels at the 4 corners of the application around the middle panel that are mostly fixed for the lifetime of the application, but contain dynamically updated data and therefore need to be implemented using backbone.js
How do I structure such an application in backbone.js. It seems to defeat the "Do not repeat" rule to implement the intial rendering for all the side panels within every route in the router as I would end up repeating the same rendering code in every route.
How do I structure my code in this instance so that I don't repeat code in multiple places.
JavaScript is like any other code: if you find yourself writing the same lines of code, extract them in to a function. If you find yourself needing to use the same function, extract it (and related functions and data) in to its own object.
So, your router shouldn't be calling your views and models directly. Instead, it should be delegating to other objects that can manipulate your views and objects.
Additionally, since your going to set up the same basic page layout every time the app starts up, you might not want that code in the router. The layout happens whether or not the router fires, and no matter which route is fired. Sometimes it's easier to put the layout code in another object, as well, and have the layout put in place before the router fires up.
MyApplication = {
layout: function(){
var v1 = new View1();
v1.render();
$("something").html(v1.el);
var v2 = new View2();
v2.render();
$("#another").html(v2.el);
},
doSomething: function(value){
// do someething with the value
// render another view, here
var v3 = new View3();
v3.render();
$("#whatever").html(v3.el);
}
}
MyRouter = Backbone.Router.extend({
routes: {
"some/route/:value": "someRoute"
},
someRoute: function(value){
MyApplication.doSomething(value);
}
});
// start it up
MyApplication.layout();
new MyRouter();
Backbone.history.start();
I've written a handful of articles relating to these things, which you might find useful:
http://lostechies.com/derickbailey/2012/02/06/3-stages-of-a-backbone-applications-startup/
http://lostechies.com/derickbailey/2011/08/30/dont-limit-your-backbone-apps-to-backbone-constructs/
http://lostechies.com/derickbailey/2011/12/27/the-responsibilities-of-the-various-pieces-of-backbone-js/
http://lostechies.com/derickbailey/2012/03/22/managing-layouts-and-nested-views-with-backbone-marionette/