Backbone Marionette: Add to region - marionette

Instead of using region.show(view), I would like to add multiple views to a region without destroying the view already present in the region. I have tried using preventDestroy: true, but it isnt working out. The region only shows the last "application".
var fetchingApplications = App.request('application:entities');
$.when(fetchingApplications).done(function(applications) {
console.log(applications);
applications.each(function(application) {
var applicationView = new List.Application({
model: application
});
App.layout.mainRegion.show(applicationView, { preventDestroy: true });
});
I know the example look weird, because I could merely use a CollectionView. However, using a CollectionView is not what I want to do.

I think it should works with dynamically add region and fadeIn. You could add class or inline style with 'display: none' so it will be initially not displayed and then in view put 'onShow : function(){ this.$el.fadeIn(); }'

Related

How to reload kendo grid with filtered data?

I have a kendo grid, in which I have selected filter on one column, I am reloading the grid, I want the same filter to be there when grid reloads.
I am using the below code to reload the grid. It works, but it doesn't show the selected filter item checked. I checked IDR in the filter then reloaded the page, it shows 1 item selected but doesn't show IDR as checked.
function ReloadGrid() {
var grid = $('#gridId').data('kendoGrid');
grid.dataSource.read();
grid.setDataSource(grid.dataSource);
}
Well there is two way to achieve this.
One way is to save filters in database and second one is to use local storage as mentioned in comment.
I prefer second one, using local storage to save filters and load it upon read.
#GaloisGirl is pointing you in right direction.
Check this example again: Persist state
Basic usage of locale storage is to save some data under some name (key,value):
let person = {
name: 'foo',
lastName: 'bar'
};
let save = function (person) {
let personString = JSON.stringify(person);
localStorage.setItem('person', personString);
console.log('Storing person: ', personString);
};
let load = function () {
let personString = localStorage.getItem('person'); // <----string
let person = JSON.parse(personString); // <----object
console.log('Stored person: ', person);
};
let remove = function (name) {
localStorage.removeItem(name);
console.log('Removed from local storage!');
};
save(person);
load();
remove(person.name);
In kendo world you need to save current options state of grid in local storage, you can achieve that by adding button like in example or on the fly with change or with window.onbeforeunload or like in your example beforen reload grid.
You can check saved data under application tab in browsers, eg. chrome:
Hope it helps, gl!

SAPUI5: Extend Control, renderer has html tags with event

I extend a Control to create a new custom control in UI5 and this control renders a tree as UL items nicely. Now I need to implement a collapse/expand within that tree. Hence my renderer writes a tag like
<a class="json-toggle" onclick="_ontoggle"></a>
and within that _ontoggle function I will handle the collapse/expand logic.
No matter where I place the _ontoggle function in the control, I get the error "Uncaught ReferenceError: _ontoggle is not defined"
I am missing something obvious but I can't find what it is.
At the moment I have placed a function inside the
return Control.extend("mycontrol",
{_onToggle: function(event) {},
...
Please note that this event is not one the control should expose as new event. It is purely for the internals of how the control reacts to a click event.
I read things about bind and the such but nothing that made sense for this use case.
Took me a few days to crack that, hence would like to provide you with a few pointers.
There are obviously many ways to do that, but I wanted to make that as standard as possible.
The best suggestion I found was to use the ui5 Dialog control as sample. It consists of internal buttons and hence is similar to my requirement: Render something that does something on click.
https://github.com/SAP/openui5/blob/master/src/sap.ui.commons/src/sap/ui/commons/Dialog.js
In short, the solution is
1) The
<a class="json-toggle" href></a>
should not have an onclick. Neither in the tag nor by adding such via jQuery.
2) The control's javascript code should look like:
sap.ui.define(
[ 'sap/ui/core/Control' ],
function(Control) {
var control = Control.extend(
"com.controlname",
{
metadata : {
...
},
renderer : function(oRm, oControl) {
...
},
init : function() {
var libraryPath = jQuery.sap.getModulePath("mylib");
jQuery.sap.includeStyleSheet(libraryPath + "/MyControl.css");
},
onAfterRendering : function(arguments) {
if (sap.ui.core.Control.prototype.onAfterRendering) {
sap.ui.core.Control.prototype.onAfterRendering.apply(this, arguments);
}
},
});
control.prototype.onclick = function (oEvent) {
var target = oEvent.target;
return false;
};
return control;
});
Nothing in the init(), nothing in the onAfterRendering(), renderer() outputs the html. So far there is nothing special.
The only thing related with the onClick is the control.prototype.onclick. The variable "target" is the html tag that was clicked.

Marionette View - unable to reuse template

I have a module called GridView in which i extend Marionette.ItemView like given below:
GridView.View = Marionette.ItemView.extend({
template: "#grid-view-template",
showGrid: function(gridName) {
....
},
....
}
Whenever a grid is to be displayed the caller extends GridView and invokes the showGrid method with a parameter (as given below)
//Module A code
var View = GridView.View.extend({
});
....
someregion.view.showGrid("GridA");
//Module B code
var View = GridView.View.extend({
});
....
someOtherregion.view.showGrid("GridB");
The problem is that when i show Grid A first and then click (on some menu) to show Grid B, i get a blank screen. If i come back to Grid A it shows the grid. If i show Grid B first, it shows the Grid but get a blank screen when Grid A is clicked. (i.e is only shows the grid which is invoked first). I can always go back to the grid that is shown first and is shows :-(
In a moment of frustration i did the following:
a) Removed the template from GridView
b) Added the template to each module
If I do this, it works as expected (code snippet below)
GridView.View = Marionette.ItemView.extend({
//template: "#grid-view-template", (COMMENTED OUT)
showGrid: function(gridName) {
....
},
....
}
//Module A code
var View = GridView.View.extend({
template: "#gridA-template",
});
....
view.showGrid("GridA");
//Module B code
var View = GridView.View.extend({
template: "#gridB-template",
});
....
view.showGrid("GridB");
When each View that extends GridView has its own template all works well - would appreciate it if someone could shed some light on this.
While this works for me, its a pain since each module that needs to show a grid needs to define its own template with a different ID
The template itself is pretty simple
<div id="grid-view-div3"></div>
thanks in advance
-joseph
Having a template in the base class and then extending views off it is definitely possible, as long as your subviews all use the same template. If the templates need to be slightly different ( not sure if you can change this ) then you can keep your base class, have and then in each subview, specify which template to use, like you are doing.
If there is a way to you to make a more general template and have all grids ( A, B, or C, ) use the same div ( from your template), then your first solution should work... it sounds like, while your putting the grid into the correct div that your template provides for module A with showGrid: function(gridName), that using the same function for modular B is looking for a different div
What exactly does showGrid: do?

Manually load kendo mobile view

I'm working on a Kendo Mobile project with a number of:
Kendo Views (external to root html)
Modal Views (in the root html).
The external files load on demand and everything works fine. But i'd like to have the same load on demand behavior for some of the modal views, because the root/based html file is becoming too large and not manageable.
Is there a way to either:
Store a modal view in an external file? If so is it possible to load via javascript syntax (app.navigate()) rather than the declarative syntax (href='externalmodal').
Manually pre-load an external view without navigating to it first.
This code lets you manually create a view:
var viewUrl = 'blahblahblah';
var element = $.parseHTML('<div data-role=view>test</div>')[0];
element.style.display = 'none';
$(document.body).append(element);
var options = $.extend({}, kendo.parseOptions(element, kendo.mobile.ui.View.fn.options));
var view = new kendo.mobile.ui.View(element, options);
view.element[0].setAttribute('data-url', viewUrl);
kendo.mobile.application.navigate(viewUrl, '');
Depending on what features you use, you may need to instead use code similar that that used for ModalView below so that Kendo creates the subclass (changes: substitute View for ModalView, substitute view for modalview, add data-url, remove call to show(), maybe check that view not already created by checking for element with matching data-url). We haven't tested setting roles.view this way, but we did something similar while testing this stuff out and it worked.
Don't try settings the options - Kendo got confused (at least trying to set useNativeScrolling didn't work, also don't try setting the options object on the subclass unless you really know what you are doing).
Caveat: This was using browserHistory:false (which disables routing) when the kendo.mobile.Application was created. The technique should still work when using browser history if you use a valid url fragment (same as would be created by Kendo for the pushstate/hashchange url).
This is a also way to cleanly subclass kendo.mobile.ui.View that works well - although you must still use data-role=view even though your subclass is a "different" component. Note that you can't just use you cant use your own subclassed component with its own name like role=myview to subclass a view because there are hard-coded checks specifically for data-role=view in the kendo codebase. Same if you wish to subclass: layout modalview drawer splitview page (amongst other hard-coded kendo ui component names - search kendo code for kendo.roleSelector - ugly). e.g.
MyView = kendo.mobile.ui.View.extend({
init: function(element, options) {
kendo.mobile.ui.View.prototype.init.apply(this, arguments);
...
var myView = new MyView('<div data-role=view>test</div>');
Why it works: The relevant function in the Kendo source code is _findViewElement which does element = this.container.children("[" + attr("url") + "='" + urlPath + "']"); to see if the view already exists for a url, before creating a new one. A unique init function is always required as it ends up being the constructor function.
If you want to subclass a modalview, you need to do something different due to the way kendo works:
var MyModalView = kendo.mobile.ui.ModalView.extend({
html: '<div data-role=modalview style="width:90%;display:none;">Foobar</div>',
init: function() {
kendo.mobile.ui.ModalView.prototype.init.apply(this, arguments);
}
});
function makeModalView() {
$(document.body).append($.parseHTML(MyModalView.prototype.html));
var roles = $.extend({}, kendo.mobile.ui.roles);
roles.modalview = MyModalView;
var modalView = kendo.initWidget($(element), {}, roles);
modalView.open();
return modalView;
}

Is it ok to use App.__container__.lookup to access instances?

I need access to the ApplicationView from another view and I'm able to do so with App.__container__.lookup('view:application').
Is __container__ intended to be used this way?
Is there a better way to access instances of views?
(update)
My usecase:
My ApplicationView has a template with 2 columns.
The CSS is responsive so the size of the columns changes to accommodate the
width of the page.
I'm using Ember List View which requires height and width to be specified during initialization
I want to get the instance so I can access the DOM object to figure out its size
I can't use Ember.View.views because at that point, the ApplicationView has not been inserted into the DOM
Don't use that. One of the core developers said that whenever someone tries to use App.__container__, he would add another underscore.
If you really want to access an Ember.View intance use Ember.View.views['foo']. Where foo is the elementId of the view instance.
So if for example you want the App.ApplicationView instance:
App.ApplicationView = Ember.View.extend({
elementId: 'application'
});
// somewhere else in your code
var applicationViewInstance = Ember.View.views['application'];
Having said that, I never came across a situation where I needed to access view instances like that. If you can post your use case, I may be able to suggest alternative ways.
UPDATE: You want to access some properties of a view instance, from some other view instance (view height and width). You can pass those properties to the controller and let other controllers access them for using them in other views (source view -> source controller -> some other controller -> some other view):
App.ApplicationView = Ember.View.extend({
didInsertElement: function() {
var controller = this.get('controller'),
height = this.$().height(),
width = this.$().width();
controller.setProperties({
height: height,
width: width
});
}
});
App.SomeotherController = Ember.Controller.extend({
needs: ['application'],
applicationViewWidthBinding: 'controllers.application.width',
applicationViewHeightBinding: 'controllers.application.height'
});
App.SomeOtherView = Ember.View.extend({
// assuming its controller is an instance of App.SomeotherController
applicationViewWidthBinding: 'controller.applicationViewWidth',
applicationViewHeightBinding: 'controller.applicationViewHeight'
});

Resources