0

apologies if it's not termed correctly, development isn't my first language :)

I'm trying to add functionality to an extjs web application called Traccar (a web based tracking platform).

For anyone familiar with the application, what I'm trying to do is add a "quick report" button to the devices section, so that you can click a device, click the button and it will expand the reports section and pre-select the report type as trips, device as the selected device and click show.

From a technical perspective, I've achived some of this. I believe that there are two view controllers that I need to be concerned about - "DevicesController.js" (https://github.com/traccar/traccar-web/blob/9e1c0b44189136ec6abf05720c698027a689fa08/web/app/view/edit/DevicesController.js) and "ReportsController.js" (https://github.com/traccar/traccar-web/blob/9e1c0b44189136ec6abf05720c698027a689fa08/web/app/view/ReportController.js)

I've worked out how to expand the reports section at the bottom of the screen (that was fairly easy):

onQuickReportClick: function() {

  Ext.getCmp('reportViewPanel').expand(true);

},

I've been trying to call across to the reports controller to interact with it, but I can't seem to get my head round how to do it (if you even can) I've been trying things like -

    var reportController = Traccar.app.getController("Traccar.view.ReportController");
    reportController.test();

But, I get an error like this

```    Uncaught TypeError: controller.doInit is not a function
```    at constructor.getController (ext-all-debug.js:95199:28)
```    at constructor.onQuickReportClick (DevicesController.js:109:38)
```    at Object.callback (ext-all-debug.js:8705:32)
```    at constructor.fireHandler (ext-all-debug.js:144259:17)
```    at constructor.onClick (ext-all-debug.js:144241:16)
```    at constructor.fire (ext-all-debug.js:20731:42)
```    at constructor.fire (ext-all-debug.js:34336:27)
```    at constructor.publish (ext-all-debug.js:34296:28)
```    at constructor.publishDelegatedDomEvent (ext-all-debug.js:34318:14)
```    at constructor.doDelegatedEvent (ext-all-debug.js:34361:16)

The test method is very simple at the moment, just to prove I'm getting there -

test: function () {
    showToast("test - succsfully in report controller", "test");
},

Any pointers / guidance / advice would be greatly appreciated

James
  • 1
  • `Traccar.view.ReportController` is a class created with `Ext.define`. In an ExtJS application there can be more instances of this. So you need to get the view instance and get the controller. For example `Traccar.getApplication().getMainView().getController()` will give you the main view`s controller. – Peter Koltai Feb 09 '22 at 18:31
  • Thanks @PeterKoltai I'lll have a go at this – James Feb 09 '22 at 20:07
  • Let me know here how it went. – Peter Koltai Feb 09 '22 at 20:12
  • Thank you, think I'm still not quite getting it thought So something like this? `var reportController = Traccar.getApplication().getMainView().getController("ReportController");` – James Feb 09 '22 at 20:33
  • No, that won't work. You need to get the view that has this type of controller. Controllers are assigned to views by instance. If it's not the main view, you need to figure out how can you get the view. – Peter Koltai Feb 09 '22 at 20:41
  • In the controller there will be functions that need a view, for example `lookup`. You can't have an "abstract" controller because controllers perform actions on a specific view instance. – Peter Koltai Feb 09 '22 at 20:43
  • I think its worth mentioning that you can use an app controller instead of a view controller. https://docs.sencha.com/extjs/6.5.3/classic/Ext.app.Controller.html – hwsw Feb 13 '22 at 18:45

2 Answers2

1

Advice

It is a NoGo to call a controller from another controller.

The controller is a viewController, created when the view is created to react to userinput from that view. Worstcase: the other view does not exist and therefore the viewController has not been created.


If you really have to

You want to follow Peters comment and run:

Ext.first('reportView').getController()
// or faster and prefered
// add an id to the view => reportViewId
Ext.getCmp('reportViewId').getController()

Way better

Make use of Events or setup your own Eventbus

Setup EventBus

after your app started call

Traccar.Bus = new Ext.util.Observable();

With that in place you can fire an event in one viewController:

/**
 * @param {string} eventName
 * @param {object} args
 */
Traccar.Bus.fireEvent(eventName, args);

In the receiving viewController you previously set a listener

onOtherViewControllerFire: function(args) {...}
init: function() {
    Traccar.Bus.on(eventName, this.onOtherViewControllerFire);
}
Dinkheller
  • 4,631
  • 5
  • 39
  • 67
  • Thank you, I'll have a look at those options, an event bus does sound like it's probbaly going to be the best way to go – James Feb 09 '22 at 21:44
1

You can use events. You don't actually need to set up a Bus for it. You can just call something like this:

this.fireEvent('selectevent', position);

And the subscribe in another place like this:

    config: {
        listen: {
            controller: {
                '*': {
                    selectdevice: 'deselectEvent',
                    selectreport: 'deselectEvent'
                },

Events are actually used a lot in the Traccar app. You can just search existing usages.

Anton Tananaev
  • 2,458
  • 1
  • 25
  • 48