angularjsangularjs-directiveangularjs-module

How to reload / recompile / refresh directive in AngularJs?


I have installed the malhar-angular-dashboard module for the purpose of using widgets. After I configure my options the dashboard-layouts directive works fine and is displaying my widgets in the view. If I change the options in my controller after the directive has compiled I get this error:

Widget fromTimeout is not found. undefined

HTML


 <div ng-controller="widgetCtrl">
  <div class="row">
    <div class="col-md-12" style="background:#B8B7C9;">
      <div ng-if="layoutOptions"
           dashboard-layouts="layoutOptions"
           class="dashboard-container"
           template-url="views/dashboards/widget-area/customDashboardLayout.tmpl.html">
      </div>
    </div>
  </div>

Chose widget - button

 <div class="btn-group" ng-if="!options.widgetButtons">
        <span class="dropdown" on-toggle="toggled(open)">
          <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
            <span class="fa fa-bars"></span> Chose widget
          </button>
          <ul class="dropdown-menu" role="menu">
            <li ng-repeat="widget in layoutOptions.widgetDefinitions"> <!-- initial was : widget in widgetDefs -->
              <a href="#" ng-click="addWidgetInternal($event, widget);" class="dropdown-toggle"><span class="label label-primary">{{widget.name}}</span></a>
            </li>
          </ul>
        </span>
</div>

JavaScript Controller


// layout with explicit save
$scope.layoutOptions = { 
        storageId: 'demo-layouts-explicit-save',
        storage: localStorage,
        storageHash: 'fs4df4d51',
        widgetDefinitions: $scope.myWidgets, // to be changed
        layoutDefinitions:widgetDefs.REQUEST_ATTRIBUTES.layouts, // to be changed
        defaultWidgets: [], 
        explicitSave: true,
        defaultLayouts: [
          {title: 'Layout 1', active: true, defaultWidgets: []}
        ]
      };

 $scope.newChanges = function(){
     $scope.layoutOptions = { 
        storageId: 'demo-layouts-explicit-save',
        storage: localStorage,
        storageHash: 'fs4df4d51',
        widgetDefinitions:[{name:"fromTimeout"}], //changed
        layoutDefinitions:[],                     //changed
        defaultWidgets: [], 
        explicitSave: true,
        defaultLayouts: [
          {title: 'Layout 1', active: true, defaultWidgets: []}
        ]
      };
 };

Running the application


  1. First load (loading layoutOptions)

    works

  2. After calling newChanges() function

    enter image description here

Conclusion


When I trigger the click event from Chose widget the addWidgetInternal($event, widget) is executed witch is leading me to this problem in the dashboard-layout directive code:

 scope.widgetDefs = new WidgetDefCollection(scope.options.widgetDefinitions);
  scope.addWidget = function (widgetToInstantiate, doNotSave) {

      if (typeof widgetToInstantiate === 'string') {
        widgetToInstantiate = {
          name: widgetToInstantiate
        };
      }

      var defaultWidgetDefinition = scope.widgetDefs.getByName(widgetToInstantiate.name); // is undefined
      if (!defaultWidgetDefinition) {
        throw 'Widget ' + widgetToInstantiate.name + ' is not found.';
      }

      // Determine the title for the new widget
      var title;
      if (!widgetToInstantiate.title && !defaultWidgetDefinition.title) {
        widgetToInstantiate.title = 'Widget ' + count++;
      }

      // Instantiation
      var widget = new WidgetModel(defaultWidgetDefinition, widgetToInstantiate);

      // Add to the widgets array
      scope.widgets.push(widget);
      if (!doNotSave) {
        scope.saveDashboard();
      }

      return widget;
    };

I guess I need to recompile the directive in order to have access to my new changes I made from my controller. Any advice ?


Solution

  • I'm not using the layout-dashboard directive, but I'm using the dashboard and widget directives. I've also struggled with this for a while regarding the use of the Kendo UI library, and found a hack to force a widget recompile.

    It started when I discovered the scope.compileTemplate() function call in the widget directive code.

    In my case, I searched for the Kendo grid class .k-grid, and found this method on the angular scope object: $angular_scope.compileTemplate();

    So in my refresh code, I first look for any Kendo grid in the DOM (another hack):

       var grids = $(angular.element(document.getElementById('dash'))).find('.k-grid');
    

    I then use _.each() to iterate the DOM elements:

      _.each(grids, function (elem) {
             var grid = $(elem).parent().find('.k-grid').data('kendoGrid');  
             // add'l code omitted...
             if (grid) {                    
                 grid.$angular_scope.compileTemplate();          // *** COMPILE TEMPLATE ***
              }
        });
    

    It's not very elegant, but it does recompile my HTML code when I'm dynamically swapping out the templateURL property of the widgets definition.

    good luck, Bob