ExtJS 4 and its new MVC: grid: how to handle keys? - javascript

I'm looking for a way to handle the key in the Grid.
I've closely followed the examples here:
http://www.sencha.com/learn/architecting-your-app-in-ext-js-4-part-1
http://www.sencha.com/learn/architecting-your-app-in-ext-js-4-part-2
http://www.sencha.com/learn/the-mvc-application-architecture/
So now everything works fine, but I'd like to handle keys in my Grid.
So I guess in the declaration "this.control({})" I should just add another event concerning userlist but it seems Grid don't have the "keypress" event.
Any idea how I should do (moreover how I should do with the new MVC pattern)?
Ext.define('GS.controller.Users', {
extend: 'Ext.app.Controller',
models: [
'User'
],
stores: [
'Users'
],
views: [
'user.List',
'user.Edit'
],
init: function () {
this.control({
/* (!) Actions in 'userlist' */
'userlist': {
selectionchange: this.userListSelectionChange,
itemdblclick: this.userEdit
},
'userlist button[action=create]': {
click: this.userCreate
},
'userlist button[action=delete]': {
click: this.userDelete
},
/* (!) Actions in 'useredit' */
'useredit button[action=create]': {
click: this.userCreateValidate
},
'useredit button[action=save]': {
click: this.userEditValidate
}
});
},
userListSelectionChange: function(grid, selections, options) {
var panel = grid.view.up('panel'),
button = panel.down('button[action=delete]');
button.setDisabled(selections.length === 0);
},
userCreate: function(button) {
/* Using Ext.create() to pass variable create:true
* instead of the shortcut:
* var view = Ext.widget('useredit');
*/
var view = Ext.create('GS.view.user.Edit', {
create:true
});
},
userCreateValidate: function(button) {
var win = button.up('window'),
form = win.down('form'),
values = form.getValues();
this.getUsersStore().add(values);
this.getUsersStore().sync();
win.close();
},
userEdit: function(grid, record) {
var view = Ext.widget('useredit');
view.down('form').loadRecord(record);
},
userEditValidate: function (button) {
var win = button.up('window'),
form = win.down('form'),
record = form.getRecord(),
values = form.getValues();
record.set(values);
win.close();
this.getUsersStore().sync();
},
userDelete: function(button) {
var panel = button.up('panel'),
selection = panel.getSelectionModel().getSelection()[0];
if (selection) {
var store = this.getUsersStore();
store.remove(selection);
store.sync();
}
}
});

Define KeyMap(s) in your launch: function() {...} right after you create the view.

Related

JS works with .include but fails with .extend

I made this JS to add a functionality on a form (backend) that computes a field when the event click is triggered. So far the code recomputes when I use ".include" but the whole JS in all views fail since I'm using ".include". When I try to use extend my code does nothing. Looks like Odoo doesn't add the extended code to the JS engine so my question is, what am I doing wrong here? Is there something else I need to add so my code works as extended?
odoo.define('med_care.TestRenderer', function (require) {
"use strict";
var viewRegistry = require('web.view_registry');
var FormRenderer = require('web.FormRenderer');
var FormView = require('web.FormView');
var TestFormRenderer = FormRenderer.extend({
events: _.extend({}, FormRenderer.prototype.events, {
'click .sign_selector': '_onSignSelectorClicked',
}),
init: function (parent, state, params) {
this._super.apply(this, arguments);
this.fields = state.fields;
this._onSignSelectorClicked = _.debounce(this._onSignSelectorClicked, 300, true);
},
confirmChange: function (state, id, fields, e) {
var self = this;
if (state.model == 'med.test') {
return this._super.apply(this, arguments).then(function () {
self.canBeSaved(self.state.id);
});
}
},
_onSignSelectorClicked: function (event) {
this.state.data.telephone = '333';
if (this.state.model == 'med.test') {
var info_test = {
dataPointID: this.state.id,
changes: {telephone: '333'},
viewType: "form",
notifyChange: true
};
var odoo_event = this.trigger_up('field_changed', info_test);
this.confirmChange(this.state, this.state.id, "telephone",
odoo_event)
}
},
});
var TestFormView = FormView.extend({
config: _.extend({}, FormView.prototype.config, {
Renderer: TestFormRenderer,
}),
});
viewRegistry.add('test_form', TestFormView);
return TestFormView;
});

Problem with variable scope in nested Backbone views

I have a parent view which contains a Backgrid view. In the parent view's initialize section I define a variable isWellSelected. The variable is toggled in the Backgrid column logic when a tickbox is checked. I am able to watch the variable toggled when a box is ticked and unticked.
However, once an event fires the variable is no longer in scope for the event to see. I suspect I may need to pass the variable to the Backrgrid view but I am unsure how to do that correctly. Please advise.
app.wellCollectionView = Backbone.View.extend({
template: _.template($('#wellTemplate').html()),
initialize: function() {
this.isWellSelected = false;
// isWellSelected toggled to true when a tickbox is checked in the columns block.
var columns = [...];
// instantiate collection
var wellCollection = new app.wellCollection;
// Set up a grid view to use the pageable collection
var wellGrid = new Backgrid.Grid({
columns: columns,
collection: wellCollection
});
// Initialize the paginator
var paginator = new Backgrid.Extension.Paginator({
collection: wellCollection
});
// Render the template
this.$el.html(this.template());
// Render the grid
this.$el.append(wellGrid.render().el);
this.$el.append(paginator.render().$el);
wellCollection.fetch({reset: true}).then(function () {...});
},
events: {
'click #EvaluateWell': function(){
this.evalWell(event, this.isWellSelected);
console.log("In events - isWellSelected: " + this.isWellSelected);}
},
// More stuff
}
Constructive feedback welcome.
Thanks!
Adding a snippet for "columns" as per JT's request:
var columns = [
{
name: '',
label: 'Select',
cell: Backgrid.BooleanCell.extend({
events : {
'change': function(ev){
var $checkbox = $(ev.target);
var $checkboxes = $('.backgrid input[type=checkbox]');
if($checkbox.is(':checked')) {
$checkboxes.attr("disabled", true);
this.isWellSelected = true;
// Disable all checkboxes but this one
$checkbox.removeAttr("disabled");
} else {
// Enable all checkboxes again
$checkboxes.removeAttr("disabled");
this.isWellSelected = false;
}
}
}
})
}, {
name: "api",
label: "API",
editable: false, // Display only!
cell: "string"
}, {
name: "company",
label: "Operator",
editable: false, // Display only!
cell: "string"
}];

Trigger function in moment column is sorted in GridX

I use SingleSort module with Gridx. I can't find (I already checked SingleSort documentation and found nothing) a way to react on sort event. I need info about which (and how) column is sorted. I know how get info about sorting (getSortData method) but i don't know how make react in moment sort is made. I can't made onRender-event function because after sorting i will send that info to webapi get new data and again render Grid so event will be triggered again.
define([
"dojo/Evented",
"dojo/_base/declare",
"dojo/store/Memory",
"gridx/core/model/cache/Sync",
"gridx/Grid",
"gridx/modules/ColumnResizer",
'gridx/modules/Focus',
'gridx/modules/RowHeader',
'gridx/modules/select/Row',
'gridx/modules/select/Column',
'gridx/modules/select/Cell',
"gridx/modules/SingleSort"
], function (Evented, declare, Memory, Cache, Grid, ColumnResizer, Focus, RowHeader, SelectRow, SelectColumn, SelectCell, Sort) {
return declare([Evented], {
_counter: 1,
_topOffset: 100,
constructor: function () {
},
initialize: function () {
this._initGrid();
this._resizeGridContainer();
},
clear: function () {
var store = new Memory({ data: [] });
this._grid.setStore(store);
this._counter = 1;
},
_initGrid: function () {
var _this = this;
var store = new Memory({
data: []
});
var structure = [
{
id: 'operationType', field: 'operationType', name: dojo.byId(this._operationTypeId).value
},
{
id: 'transportationType', field: 'transportationType', name: dojo.byId(this._transportationUnitTypeId).value
},
{
id: 'transportationTypeLength', field: 'transportationTypeLength', name: dojo.byId(this._transportationLengthId).value
}
]
this._grid = Grid({
id: this._gridId,
cacheClass: Cache,
store: store,
structure: structure,
modules: [
ColumnResizer,
Sort
],
selectRowTriggerOnCell: true
});
this._grid.placeAt(this._gridPlaceholderId);
this._grid.startup();
},
_resizeGridContainer: function () {
var _this = this;
var container = dojo.byId(this._gridContainerId);
var height = container.parentElement.clientHeight - this._topOffset;
require(["dojo/dom-style"], function (domStyle) {
domStyle.set(_this._gridContainerId, "height", height + "px");
})
},
});
});
you need to tap on to the gridx SingleSort module sort method like this
this._grid.connect( this._grid.Sort, 'sort', function(colId, isDescending, skipUpdateBody){
alert(colId+" "+isDescending+" "+skipUpdateBody);
});
this will trigger the event whenever a grid column is sorted. Hope this helps.

Stateful selection in Ext JS

I have a regular tree with elements. What i want to do is following:
When I reload the page, the selected item must be the same as before ( I select only 1 item in the tree).
For example, when I click on 'Sue Potato' - it is selected and when I refresh the page, it must look the same (be also selected).
I've tried reading some Stateful, Provider, Manager on the Sencha Docs, but I didn't get it.
Controller code:
Ext.define('FirstApp.controller.Main', {
extend: 'Ext.app.Controller',
refs: [
{
ref: 'grid',
selector: 'lesson-grid'
},
{
ref: 'tree',
selector: 'school-tree'
}
],
init: function() {
Ext.state.Manager.setProvider(Ext.create('Ext.state.LocalStorageProvider'));
}
});
Tree code:
Ext.define('FirstApp.view.SchoolTree', {
extend: 'Ext.tree.Panel',
xtype: 'school-tree',
stateful: true,
stateId: 'stateGrid',
stateEvents:['selection'],
constructor: function() {
var that = this;
this.store = Ext.create('FirstApp.store.School');
this.store.on('load', function () {
that.getSelectionModel().select(1, true);
});
this.callParent(arguments);
this.getState = function() {
return that.getSelectionModel().getSelection();
};
this.applyState = function() {
};
}
});
Help would be much appreciated.
This is a working code of the requirement above.I had to get an id of the selected element and then pass it to applyState.
Ext.define('FirstApp.view.SchoolTree', {
extend: 'Ext.tree.Panel',
xtype: 'school-tree',
stateful: true,
stateId: 'stateTree',
stateEvents:['selectionchange'],
constructor: function() {
var that = this;
this.store = Ext.create('FirstApp.store.School');
this.store.on('load', function () {
that.getSelectionModel().select(1);
});
this.callParent(arguments);
},
getState: function() {
return {
'stateTree': this.getSelectionModel().getSelection()[0].getId()
};
},
applyState: function(state) {
var me = this;
this.store.on('load', function(record) {
record = this.getById(state.stateTree);
me.getSelectionModel().select(record);
});
}
});
You stored tree state and set it into State Manager
Ext.state.Manager.setProvider(Ext.create('Ext.state.LocalStorageProvider'));
So when you will refresh your page state will apply and an item will be also selected.
Is there any requirement to store state of tree? If yes and still you don't want to selected then you can forcefully clear selection on tree render.

How can i call function on view on the click event of Id, function is written on controller in backbone.js

My controller code is here.
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
"use strict";
communityApp.Controllers.pforumController = Marionette.Controller.extend(
{
init: function(){
var func = _.bind(this._getpforum, this);
var request = App.request('alerts1:entities' , {origin:'pforum'});
$.when(request).then(func)
},
_getpforum:function(data){
var pforumCollectionView = new communityApp.CollectionViews.pforumCollectionViews({
collection: data
});
communityApp.activeTabView = pforumCollectionView;
// Populating the data
communityApp.activeTabLayout.pforum.show(pforumCollectionView);
},
});
});
view code is here
spine.module("communityApp", function (communityApp, App, Backbone, Marionette, $, _) {
// Load template
var a;
var pforumTemplateHtml = App.renderTemplate("pforumTemplate", {}, "communityModule/tabContainer/pforum");
// Define view(s)
communityApp.Views.pforumView = Marionette.ItemView.extend({
template: Handlebars.compile($(pforumTemplateHtml).html()),
tagName: "li",
onRender: function () {
this.object = this.model.toJSON();
},
events: {
"click #postcomment" : "alrt",
"click #recent-btn": "recent",
"click #my-posts": "myposts",
"click #popular-btn": "popular",
"click #follow-btn": "follow",
"click #my-posts": "LeftLinks",
"click #popular-btn": "LeftLinks",
"click #follow-btn": "LeftLinks"
},
postcomments : function ()
{
$("#recent-post-main-container").hide();
$("#recent-post-main-container2").show();
},
alrt : function ()
{
alert ("In Progress ......");
},
showCommentEiditor : function (){
$(".comment-popup-container").show();
$(".comment-txt-area").val('');
},
showPforumTab : function ()
{
$("#recent-post-main-container2").show();
$("#recent-post-main-container").hide();
},
showComments : function(){
$("#loading").show();
$(".tab-pane").hide();
$(".left-content").hide();
$("#recent-post-main-container2").show();
//$(".left-content-commentEditor").show();
$(".comm-tab-content-container").css('height','200px');
$(".comment-txt-area").val('');
$(".left-content-comment").show();
},
hideCommentPopup : function ()
{
$("#public-question-comment").hide();
},
// Show Loading sign
showLoading : function () {
$('#loading').show();
},
// UnLoading Function
hideLoading : function (){
$('#loading').hide();
},
// Add New Event Function
addEvent : function()
{
//$("#name").val(getBackResponse.user.FullName);
//$("#phone").val(getBackResponse.user.CellPhone);
//$("#email").val(getBackResponse.user.UserName);
$(".overly.addevent").show();
$('#lang').val(lat);
$('#long').val(long);
document.getElementById("my-gllpMap").style.width = "100%";
var my_gllpMap = document.getElementById("my-gllpMap");
google.maps.event.trigger( my_gllpMap, "resize" );
},
setValues : function(key,value)
{
window.localStorage.setItem(key,value);
},
getValues : function (key)
{
return window.localStorage.getItem(key);
},
closeAddEvent:function ()
{
$(".overly.addevent").hide();
},
// Show Over lay
showOverly:function ()
{
$('.overly-right-tab').show();
},
// Hide Loading sign
hideOverly : function()
{
$('.overly-right-tab').hide();
},
LeftLinks: function (e) {
var elem = $(e.target).closest('a');
var elem = $(e.target).closest('a');
var event = elem.attr('name');
switch (event) {
case "myposts":
var _this = $.extend({}, this, true);
_this.event = 'myposts';
this.LinkUrl.call(_this);
//$("#my-posts").addClass('active');
//$("#public-fourm-top-tab").addClass('TabbedPanelsTabSelected');
//$(".types").removeClass('active');
break;
case "recents":
var _this = $.extend({}, this, true);
_this.event = 'recents';
this.LinkUrl.call(_this);
$(".types").removeClass('active');
$("#recent-btn").addClass('active')
//$("#pforum").removeClass('active');
// $("#recent").addClass('active');
break;
case "populars":
var _this = $.extend({}, this, true);
_this.event = 'populars';
this.LinkUrl.call(_this);
$(".types").removeClass('active');
$("#popular-btn").addClass('active')
// $("#pforum").removeClass('active');
//$("#popular").addClass('active');
break;
case "follows":
var _this = $.extend({}, this, true);
_this.event = 'follows';
this.LinkUrl.call(_this);
$(".types").removeClass('active');
$("#follow-btn").addClass('active')
break;
}
},
LinkUrl: function (modalThis) {
communityApp.activeTabView.collection = []; // currently empty data
communityApp.activeTabView.render();
className: 'comm-main-container'
// uncomment these lines when getting data fro web service route, it will repopulate the data
var func = _.bind(function (data) {
communityApp.activeTabView.collection = data;
communityApp.activeTabView.render();
}, this);
switch (this.event) {
case "myposts":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
event: this.event
})).then(func);
break;
case "recents":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
event: this.event
})).then(func);
break;
case "populars":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
origin1:'popular',
event: this.event
})).then(func);
break;
case "follows":
$.when(App.request('alertLinks:entities', {
origin: 'pforum',
event: this.event
})).then(func);
break;
}
return true;
}
});
// define collection views to hold many communityAppView:
communityApp.CollectionViews.pforumCollectionViews = Marionette.CollectionView.extend({
tagName: "ul",
itemView: communityApp.Views.pforumView
});
});
Whenever I need to share an event between a view and controller I usually wire up the listeners within the module that instantiates the controller. This example is a bit contrived, but it gets the point across. The full working code is in this codepen. The relevant bit is copied here. Notice the line this.listenTo(view, 'itemview:selected', this.itemSelected); where the view's event triggers a method on the controller.
App.module("SampleModule", function(Mod, App, Backbone, Marionette, $, _) {
// Define a controller to run this module
// --------------------------------------
var Controller = Marionette.Controller.extend({
initialize: function(options){
this.region = options.region
},
itemSelected: function (view) {
var logView = new LogView();
$('#log').append(logView.render('selected:' + view.cid).el);
},
show: function(){
var collection = new Backbone.Collection(window.testData);
var view = new CollectionView({
collection: collection
});
this.listenTo(view, 'itemview:selected', this.itemSelected);
this.region.show(view);
}
});
// Initialize this module when the app starts
// ------------------------------------------
Mod.addInitializer(function(){
Mod.controller = new Controller({
region: App.mainRegion
});
Mod.controller.show();
});
});
The other way to accomplish this, if you cannot wire it all up within the same module, is to use Marionette's messaging infrastructure. For example, you can use the application's event aggregator to pass events around.

Categories

Resources