Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget to Widget Interaction #126

Open
rsnelling opened this issue Mar 19, 2015 · 4 comments
Open

Widget to Widget Interaction #126

rsnelling opened this issue Mar 19, 2015 · 4 comments

Comments

@rsnelling
Copy link

Andy/Nick,

We're working through a prototype of the dashboard for a patient care application. We implemented several of the NVD3 widgets and have started building custom widgets with data from our REST API's. One thing we're investigating is how to have one widget effect the scope of another. For instance in a patient roster table widget, if we select a patient then we'd like to update additional widgets (ie. contact information widget or patient medication history widget) to reflect the data of the patient selected in the roster widget.

I'm working through gathering a better understanding of how the widget scope relates to the dashboard controller scope but can't see how to get a handle into other widgets. Any thoughts or suggestions in regards to this?

Thanks,
Robert

@awashbrook
Copy link
Contributor

Hi Robert,

This is something I'm also working through this week. It would be good to get wider feedback on my approach to achieve the same thing using malhar.

Should highlight that we are using malhar data layers and data options with common data prototypally inherited by various kinds of widgets, e.g. this WDO:

{
  name: 'widget inheriting common data',
  directive: 'widget-rendering-some-data-model',
  dataModelType: SomeDataModelExtendingCommonData,
  dataModelOptions: {
    common: {
      data: 'initial value'
    },
    settingsModalOptions: {
      settingsModalOptions: {
        templateUrl: 'src/controllers/widgetOptions.html',
        controller: 'widgetOptionsController'
      },
      onSettingsClose: function (result, widget, dashboardScope) {
        console.log('Widget specific settings resolved.');
        if (!angular.equals(result.dataModelOptions.common, widget.dataModelOptions.common)) {
          dashboardScope.$broadcast('commonDataChanged', newWidget.dataModelOptions.common);
        }
      },
      onSettingsDismiss: function (reason, dashboardScope) {
        console.log('Widget-specific settings have been dismissed: ', reason);
      }
    }
  }
}

Each widget will persist all data in full, but I am synchronizing common data across our dashboard using angular events. Lets assume that all of our widgets inherit the method setCommon(data) from the following angular service:

.factory('CommonDataModel', function (WidgetDataModel) {
  function CommonDataModel() {}

  CommonDataModel.prototype = Object.create(WidgetDataModel.prototype);

  CommonDataModel.prototype.setup = function (widget, scope) {
    WidgetDataModel.prototype.setup.call(this, widget, scope);

    this.dataModelOptions = this.dataModelOptions || {};
    this.dataModelOptions.common = this.dataModelOptions.common  ||  { data: 'default value' };
    ...
    scope.$on('commonDataChanged', function (event, data) {
      console.log('Common data changed for: ' + this.widgetScope.widget.title);
      this.setCommon(data);
    }.bind(this));
  };

  CommonDataModel.prototype.setCommon = function (data) {
    if (data && (!angular.equals(this.dataModelOptions.common, data))) {
      console.log(this.widgetScope.widget.title + ' data model options changed');

        this.dataModelOptions.common = data;
      ...
      this.widgetScope.$emit('widgetChanged', this.widgetScope.widget);
    }
  };
  ...
}

Now every time someone hits ok on the modal, any change in the common settings is detected and broadcast to all those inheriting this data.

@andyperlitch, please let me know what you think of this solution? Feel I may be missing something regarding appropriate use of dataModelOptions vs dataModel, as per your example https://github.com/DataTorrent/malhar-angular-dashboard/blob/aebd4b9cf44d2ee5222b56a5847c61cbfb441b67/src/app/customWidgetSettings.js

@andyperlitch
Copy link
Collaborator

@awashbrook I like your approach, and would be similar to the approach I myself would take.

@rsnelling, I think the main idea you should extrapolate from andy's comments is to use scope.$broadcast on the dashboard scope. In his specific case, the onSettingsClose method conveniently gets the dashboard scope as a third argument.

If in your specific use-case you would like to trigger changes directly from the widget itself (i.e. not opening the settings dialog), you could do something like this.widgetScope.$parent.$broadcast('someEvent', { some: 'data' });, then have other widgets listen for this event.

If you need more explanation, I'll be happy to elaborate further. I highly recommend reading through the docs for $broadcast and $emit on the angular scope API page.

Also, I'd love to work an example that does something like this into our demo. I am pretty swamped with work at the moment, but if I can find some time, I'll certainly try and get to it and notify you all.

Best,
Andy

@awashbrook
Copy link
Contributor

Thanks Andy, yes the discovery that dashboard scope was passed as the
mysterious third argument, was a most pleasant, surprise as I was expecting
to have to solve this the hard way :)

On Thursday, 19 March 2015, Andy Perlitch [email protected] wrote:

@awashbrook https://github.com/awashbrook I like your approach, and
would be similar to the approach I myself would take.

@rsnelling https://github.com/rsnelling, I think the main idea you
should extrapolate from andy's comments is to use scope.$broadcast on the
dashboard scope. In his specific case, the onSettingsClose method
conveniently gets the dashboard scope as a third argument.

If in your specific use-case you would like to trigger changes directly
from the widget itself (i.e. not opening the settings dialog), you could do
something like this.widgetScope.$parent.$broadcast('someEvent', { some:
'data' });, then have other widgets listen for this event.

If you need more explanation, I'll be happy to elaborate further. I highly
recommend reading through the docs for $broadcast and $emit on the angular
scope API page https://docs.angularjs.org/api/ng/type/%24rootScope.Scope
.

Also, I'd love to work an example that does something like this into our
demo. I am pretty swamped with work at the moment, but if I can find some
time, I'll certainly try and get to it and notify you all.

Best,
Andy


Reply to this email directly or view it on GitHub
#126 (comment)
.

@robertmazzo
Copy link

This is interesting also because in my case I'd like a chart in one widget to update a chart or grid in another. I'm seeing that I could use this.widgetScope.$parent.$broadcast('someEvent', { some: 'data' });, then have other widgets listen for this event

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants