0

Supposedly, I have a directive with scope

scope: {
   columns: '=',
}

How can I achieve this?

<my-directive columns="[{ field:'id', displayName: 'ID' },
                            { field:'title', displayName: 'Title' },
                            { field:'address', displayName: 'Address' },
                            { field:'city', displayName: 'City' }]" />

Apparently Angular's compiler have problems with figuring out that it's an array, although it doesn't have a problem with standard JS objects passed this way - {}. Is there any nifty way to do this? Does the fact that it works with objects is just a coincidence?

Please keep in mind that I know, that I can set this as $scope parameter in Controller and pass just the parameter name from $scope. But I would really like to learn if it's possible to do it straight from HTML.

-- Update with full code:

This is how it is used in template

<es-paged-data-grid columns="[
                                { field:'id', displayName: 'ID' },
                                { field:'title', displayName: 'Title' },
                                { field:'address', displayName: 'Address' },
                                { field:'city', displayName: 'City' }
                            ]">
</es-paged-data-grid>

This is the directive:

app.directive('esPagedDataGrid', function () {
    var definition = {
        restrict: "E",
        replace: false,
        transclude: true,
        scope: {
            columns: '=',
        },
        templateUrl: 'application/directive/pagedDataGrid/PagedDataGrid.html',
        controller: ['$scope', '$element', '$attrs', '$transclude', function($scope, $element, $attrs, $transclude) {

            var dataGridOptions = {};

            if ($scope.columns) {
                dataGridOptions.columnDefs = $scope.columns;
            }

            $scope.dataGridOptions = dataGridOptions;
        }]
    };

    return definition;
});

This is the directive's template:

<div ng-grid="dataGridOptions">
</div>
4
  • Why you don't want to define array in controller? HTML seems a bit messy by form you wrote it (aka hardcoded) Commented Jun 5, 2014 at 14:32
  • I would try to wrap ALL strings in array with '. Not only values but keys also Commented Jun 5, 2014 at 14:33
  • Please, don't go the "why would want to do that" route. You think it's messy like this. I think it's messy to throw configuration variables that are strictly presentation-related into controller. Let's not discuss this. Commented Jun 5, 2014 at 14:42
  • Using ' doesn't work, unfortunately. My example doesn't work as it is - it throws "Error: [$compile:nonassign] Expression used with directive is non-assignable!" Commented Jun 5, 2014 at 14:43

2 Answers 2

1

You have mentioned in one of your comments that your directive throws a nonassign error. A nonassign error occurs when a directive attempts to modify an isolate scope defined using the = notation wherein the assigned attribute is an expression that is not two-way data bound(not a scope variable).

Probably somewhere in your directive, you may have attempted to change scope.columns directly such as, scope.columns = []; or any other scope property that is assigned via the = notation. Try removing that and it might solve your problem.

UPDATE:

trying changing this:

 dataGridOptions.columnDefs = $scope.columns;

to this:

 dataGridOptions.columnDefs = angular.copy($scope.columns);

I suspect the ng-grid directive is probably doing some manipulation on the columnDefs options, since columnDefs has a direct reference towards $scope.columns property then any manipulation performed in the columnDefs options would likely affect $scope.columns.

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

5 Comments

Hm... you might be onto something here. I've updated my question with my code. Could you take a look at it? I'm not modifying scope.columns, but I'm assigning it to another variable which is then assigned to new scope property. It would look like this cycle is problematic. But, there more I look at it, the more I'm convinced that using = is just an error here. I should use @, as there's no chance for proper binding between directive's scope variable and parent's scope variable, since I'm not specifing it's name, but putting array directly. Right? The error is just a consequence (right?)
Hmm it might be better to create a plunker and recreate the problem altogether for everyone to assess the problem. Using the @ notation on the other hand is simply passing a string to the allocated scope variable. It might work if you use scope.$eval() on the scope attribute property and therein manipulate the data at hand. If you are not restricted in maintaining the directive's state via directive controllers, you can simply access the string in the attr argument e.g. attr.columns and scope.$eval() it for manipulation.
That's what I ended up doing it so far it's working fine. But I would still like to know what is going when using = and why it seems so unpredictable. Unfortunately, I'm not familiar with plunkr, but I've written all the parts in original question.
Yup, that was it! So, let me get this straight - because this was passed to ng-grid, when it manipulates the whole dataGridOptions object, it triggers bind updates to $scope.columns (which then fail, because they cannot be bound to anything). Since we're doing a (deep?) copy, ng-grid manipulations don't trigger bind updates in original $scope.columns?
Thanks for helping me with this, much appreciated!
1

Well AFAIK i guess a way to initialize data in DOM is using the ng-init directive. So the directive can look like,

app.directive('testd', function() {
  return {
    scope: {
      options: "=ngInit"
    },
    link: function(scope, e, a) {
      console.log('test', scope.options);
    },
    template: 'test'
  };
});

And you can supply the array via ng-init,

<div testd ng-init="[{ field:'id', displayName: 'ID' },
                            { field:'title', displayName: 'Title' },
                            { field:'address', displayName: 'Address' },
                            { field:'city', displayName: 'City' }]"></div>

Sample Demo: http://plnkr.co/edit/MwOPLm16KTOr2Q3rY6LK?p=preview

Well one more way would be to pass it via an attribute. Though it will be taken as string, you can use eval() to convert it to object and assign it to a scope variable. Plnkr is also updated for the same. Included columns:"@" and use eval(attrs.columns) to convert it to array

6 Comments

It certainly is a way, but feels a bit too hacky for now. Are there any others?
Well one more way would be to pass it via an attribute. Though it will be taken as string, you can use eval() to convert it to object and assign it to a scope variable. i have updated my plnkr - plnkr.co/edit/MwOPLm16KTOr2Q3rY6LK?p=preview
this is working fine even with normal scope binding between directive and dom i guess your array syntax is wrong
can you check the plnkr again please. i have updated it
Yes, this works. The problem lies somewhat deeper, it seems. My error was showing up for another directive within, that got this argument passed. It would be hard to explain without pasting lots of code and I still have no idea what's wrong with it.
|

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.