Search code examples
angularjscodemirror

How to use a variable to pass an object key into an Angular Directive?


I'm using the Code Mirror directive to format text areas as code.

What is working:

<textarea ui-codemirror type="textarea" ng-model="x"></textarea>

You can set the options up like so

<textarea ui-codemirror="editorOptions" type="textarea" ng-model="x"></textarea>

and in your Controller:

$scope.editorOptions = {
            name: 'javascript',
            json: true,
            smartIndent: false,
            tabSize: 2,
            lineWrapping : true,
            lineNumbers: true,
            mode: 'javascript'
        }

What's not working:

I'm trying to dynamically change the editorOptions based on another part of the model (I'm supporting Javascript and Markdown).

So I'm trying this:

$scope.editorOptions = {
        json: {
            name: 'javascript',
            json: true,
            smartIndent: false,
            tabSize: 2,
            lineWrapping : true,
            lineNumbers: true,
            mode: 'javascript'
        },
        markdown: {
            name: 'markdown',
            json: false,
            smartIndent: false,
            tabSize: 2,
            lineWrapping : true,
            lineNumbers: true,
            mode: 'markdown'
        }
    };

and then this in the HTML:

<select ng-model='editorType' required ng-options='option.value as option.name for option in editorTypes'></select>
<textarea ui-codemirror="editorOptions[editorType]" type="textarea" ng-model="x"></textarea>

My question is- How can I use the value of the select model (editorType) to specify which options object is being used in the code mirror directive?

I've tried

<textarea ui-codemirror="editorOptions.[editorType]" type="textarea" ng-model="x"></textarea>
<textarea ui-codemirror="editorOptions[$scope.editorType]" type="textarea" ng-model="x"></textarea>

all to no avail.

Anyone know what the proper way to do this is?

Many, many thanks!

Update I believe this is the correct syntax:

ui-codemirror="editorOptions[editorType]".

I think there is a problem with the directive not realizing the variable has changed.


Solution

  • I don't think this will work for you without forking ui-codemirror. The code within UI-codemirror does opts = angular.extend({}, options, scope.$eval(attrs.uiCodemirror)); at the beginning, but it does not watch for updates.

    If you forked ui-codemirror from: https://github.com/angular-ui/ui-codemirror/blob/master/ui-codemirror.js and then added something like

    attrs.$observe('uiCodemirror', function (newVal, oldVal) {
      if (newVal !== oldVal) {
        opts = angular.extend({}, options, scope.$eval(attrs.uiCodemirror));
        codeMirror = CodeMirror.fromTextArea(elm[0], opts); //or maybe $timeout(deferredCodemirror) ??
      }
    });
    

    Then it might work, but I haven't tested that so I have no idea if it really would work. Maybe this will give you an idea of how to create the directive you need.

    Another alternative, which would be considerably heavier, would be to instantiate two codemirrors and switch between the two... but I really don't like that option too much.