Q:

template function not interpolating component bindings

I'm  using 1.5 components, I don't think that matters though.
I'm trying to do a single = binding between a parent controller and a child directive isolate scope. The child isolate scope is interpolating the binding literally; instead of vm.data interpolating to the data I defined in the controller, it's coming out literally vm.data as a string.
If I try one way binding with @ then, again, the "interpolated" value results in {{vm.data}} literally.
How can I get the string defined in the parent controller into the child component's template?
angular
  .module('app', [])
  .controller('Ctrl', function () {
    this.str = '<0>, blah, <1>';
  })
  .component('appComponent', {
    restrict: 'E',
    controller: 'Ctrl as vm',
    template: '<div><app-str appstr-data="{{vm.str}}"></app-str></div>'
  })
  .component('appStr', {
    bindings: { appstrData: '@' },
    restrict: 'EA',
    template: function($element, $attrs) {
      console.log($attrs.appstrData)
      return '<span>'+$attrs.appstrData+'</span>';
    }
  });

https://plnkr.co/edit/VWVlhDbhP2uDRKtXJZdE?p=preview

A:

If you wanted to get the string defined in parent controller to get render in child you should use {{appStr.appstrData}} interpolation only to use it inside child template.
Very first thing you need to change is, you are returning incorrect template from appStr template.
Instead of 
return '<span>'+$attrs.appstrData+'</span>';

Use
return '<span>{{appStr.appstrData}}</span>';

Basically you should use component name to have access to component bindings, like here component name is appStr so that's why binding of variable could be accessible using {{appStr.appstrData}}
Component
.component('appStr', {
    bindings: { appstrData: '@' },
    restrict: 'EA',
    template: function($element, $attrs) {
      return '<span>{{appStr.appstrData}}</span>'; //<--change here
    }
});

Demo Plunkr

Plunkr with = binding

Plunkr with no bindings (isolate: false) means no isolated scope

