Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular 1.5 component / default value for @ binding

Is there any way to specify the default value for an @ binding of a component.

I've seen instruction on how to do it with directive: How to set a default value in an Angular Directive Scope?

But component does not support the compile function.

So, I have component like this:

{
  name: 'myPad',
  bindings   : {layout: '@'}
}

I want to free users of my component from having to specify the value of the 'layout' attribute. So..., this:

<my-pad>...</my-pad>

instead of this:

<my-pad layout="column">...</my-pad>

And... this 'layout' attribute is supposed to be consumed by angular-material JS that 'm using, so it needs to be bound before the DOM is rendered (so the material JS can pick it up & add the corresponding classes to the element).

update, some screenshots to clarify the situation:

Component definition:

{
  name : 'workspacePad',
  config : {
    templateUrl: 'src/workspace/components/pad/template.html',
    controller : controller,
    bindings   : {
      actions: '<', actionTriggered: '&', workspaces: '<', title: '@',
      flex: '@', layout: '@'
    },
    transclude: {
      'workspaceContent': '?workspaceContent'
    }
  }
}

Component usage:

<workspace-pad flex layout="column" title="Survey List" actions="$ctrl.actions"
  action-triggered="$ctrl.performAction(action)">
  <workspace-content>
    <div flex style="padding-left: 20px; padding-right: 20px; ">
      <p>test test</p>
    </div>
  </workspace-content>
</workspace-pad>

I want to make that "flex" and "layout" in the second screenshot (usage) optionals.


UPDATE

My "solution" to have this in the constructor of my component:

this.$postLink = function() {
  $element.attr("flex", "100");
  $element.attr("layout", "column");
  $element.addClass("layout-column");
  $element.addClass("flex-100");
}

I wish I didn't have to write those last 2 lines (addClass)... but well, since we don't have link and compile in component.... I think I should be happy with it for now.

like image 490
Cokorda Raka Avatar asked Jan 04 '17 15:01

Cokorda Raka


People also ask

What is bindings in AngularJS component?

Data binding in AngularJS is the synchronization between the model and the view.

What is Oninit in AngularJS?

OnInitlinkA lifecycle hook that is called after Angular has initialized all data-bound properties of a directive.

What is $Ctrl in AngularJS?

$ctrl is the view model object in your controller. This $ctrl is a name you choose (vm is another most common name), if you check your code you can see the definition as $ctrl = this; , so basically its the this keyword of the controller function.

What is one time binding in AngularJS?

At a high-level, one-time data binding means that the template is rendered once based on the current $scope and then it never updates.


3 Answers

First of there is great documentation for components Angularjs Components`. Also what you are doing I have done before and you can make it optional by either using it or checking it in the controller itself.

For example you keep the binding there, but in your controller you have something like.

var self = this;

// self.layout will be the value set by the binding.

self.$onInit = function() {
    // here you can do a check for your self.layout and set a value if there is none
    self.layout = self.layout || 'default value'; 
}

This should do the trick. If not there are other lifecycle hooks. But I have done this with my components and even used it in $onChanges which runs before $onInit and you can actually do a check for isFirstChange() in the $onChanges function, which I am pretty sure will only run once on the load. But have not tested that myself.

There other Lifecycle hooks you can take a look at.

Edit

That is interesting, since I have used it in this way before. You could be facing some other issue. Although here is an idea. What if you set the value saved to a var in the parent controller and pass it to the component with '<' instead of '@'. This way you are passing by reference instead of value and you could set a watch on something and change the var if there is nothing set for that var making it a default.

With angularjs components '@' are not watched by the component but with '<' any changes in the parent to this component will pass down to the component and be seen because of '<'. If you were to change '@' in the parent controller your component would not see this change because it is not apart of the onChanges object, only the '<' values are.

like image 199
mjwrazor Avatar answered Nov 13 '22 00:11

mjwrazor


To set the value if the bound value is not set ask if the value is undefined or null in $onInit().

const ctrl = this;
ctrl.$onInit = $onInit;
function $onInit() {
  if (angular.isUndefined(ctrl.layout) || ctrl.layout=== null)
    ctrl.layout = 'column';
}

This works even if the value for layout would be false.

like image 34
flob Avatar answered Nov 12 '22 23:11

flob


Defining the binding vars in constructor will just initiate the vars with your desired default values and after initialization the values are update with the binding.

    //ES6
    constructor(){
      this.layout = 'column';
    }
    $onInit() {
      // nothing here
    }
like image 1
Anil Maharjan Avatar answered Nov 13 '22 00:11

Anil Maharjan