1

I'm sure I've messed something up in the chain but here goes:

I have a bunch of "widget form" directives which I need to conditionally display based on which widget type the user selects. For example, if the user selects the bar chart I need to display the directive. I've achieved that using $compile which is a fairly simple directive. What I'm struggling with is trying to pass the result of the bar chart form out.

The order goes like this:

  • Open modal
  • Pick widget type (modal has an ng-switch which will display the next directive)
  • $compile < widget-form-compiler widgetType="$ctrl.widgetType" output="$ctrl.output" >
  • Which should render < bar-chart-form output="$ctrl.output" >
  • But instead it renders as < bar-chart-form output="'undefined'" >

The "output" is being evaluated instead of being passed through as a reference I think.

I'd really appreciate any help on this. This is the last chain in the link.

If the code example below is not detailed enough I can make a JSFiddle to demonstrate my problem if necessary.

UPDATE: if I change the widget-compiler directive to this: output="$parent.$ctrl.output" I can access it in the controller it was called from. Of course, this makes sense, but how can I dynamically do this?

(function() {
  'use strict';

  angular
    .module('optimizeDashboards')
    .directive('widgetFormCompiler', widgetFormCompiler);

  widgetFormCompiler.$inject = ['$compile'];

  function widgetFormCompiler($compile) {
    // Usage: Generates a widget.
    var directive = {
      link: link,
      restrict: 'E',
      scope: {
        widgetType: '=',
        output: '='
      }
    };
    return directive;

    function link(scope, element, attrs) {
      var convertedWidgetType = scope.widgetType.widgetName.toDash() + "-form";
      var generatedTemplate = '<' + convertedWidgetType + ' output="\'' + scope.output + '\'" widget-type="\'' + scope.widgetType + '\'"></' + convertedWidgetType + '>';
      element.append($compile(generatedTemplate)(scope));
    }
  }

})();


(function() {
  'use strict';

  angular
    .module('optimizeDashboards')
    .component('barChartForm', {
      template: ` * The form is pretty big plus is not the issue so I have removed it from this example for the sake of brevity * `,
      controller: BarChartFormController,
      controllerAs: '$ctrl',
      bindings: {
        output: '='
      }
    });


  BarChartFormController.$inject = ['$timeout', 'languageService', 'barChartFormService', '$uibModalStack', 'widgetFormModalService'];

  function BarChartFormController($timeout, languageService, barChartFormService, $uibModalStack, widgetFormModalService) {

    var $ctrl = this;

    $ctrl.$onInit = function() {
      $ctrl.translation = languageService;
      $ctrl.widgetObject = {};
      $ctrl.widgetObject.parameters = {};
    };

    $ctrl.cancelModal = cancelModal;
    $ctrl.saveWidget = saveWidget;

    function cancelModal() {
      $uibModalStack.dismissAll('cancel');
    }

    function saveWidget() {
      // $ctrl.widgetObject is the final object processed by the form. if console logged in this function it outputs when submit is pressed.
      $ctrl.output = $ctrl.widgetObject;
    }

  }
})();

1 Answer 1

1

You need to pass your view model manually into your compile scope. Currently $ctrl.output is undefined thats why it does result in a undefined string after compile. The compile function itself does not evaluate your params. It just tries to compile it. In that way undefined params result in an undefined string output.

View

<widget-form-compiler widgetType="$ctrl.widgetType" 
                      view-model="$ctrl" 
                      output="$ctrl.output">
</widget-form-compiler>

Directive

function widgetFormCompiler($compile) {
    // Usage: Generates a widget.
    var directive = {
        link: link,
        restrict: 'E',
        scope: {
            widgetType: '=',
            output: '=',
            viewModel: '='
        }
    };
    return directive;

    function link(scope, element, attrs) {

        scope.$ctrl = scope.viewModel;

        var convertedWidgetType = scope.widgetType.widgetName.toDash() + "-form";
        var generatedTemplate = '<' + convertedWidgetType + ' output="\'' + scope.output + '\'" widget-type="\'' + scope.widgetType + '\'"></' + convertedWidgetType + '>';
        element.append($compile(generatedTemplate)(scope));
    }
}

> demo fiddle or debug demo fiddle

Sign up to request clarification or add additional context in comments.

1 Comment

Ah, fantastic. Thanks so much! :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.