Question

I am experimenting with using React js with Angular to iterate over items, and build the needed templates as I'm experiencing speed/organizational issues with doing it the Angular way. I'm iterating over an array of items and creating new child scopes for each item and building the markup in react using that data. My question is, is there any way to attach the newly added child scope to an existing controller, so to connect any methods/variables that controller has?

Here's the React markup which has access to the parent scope and creates the child. I would like to bind a sample controller name 'CtrlItem' for example. Is this sort of thing possible?

var feedRepeat = React.createClass({
    render: function () {
        var template,
            parent = this.props.scope,
            child;

        return (
            <div>
                {parent.items.list.map(function(item, i) {
                    if (!MVItems[item.type]) { return false; }

                    template = MVItems[item.type];
                    child = parent.$new(true)
                    child.data = item;

                    return (
                        <template scope={child} />
                    )
                }, this)}
            </div>
        )
    }
})

var MVItems = Object of templates...

Update
Here's the angular mess I'm trying to work around. Basically I'm loading an extra template via ng-include because angular won't let me load a dynamic template upon directive instantiation. I feel there must be a better way to compile a template than with ng-include or ng-switch

// main-view.html
<div class="results">
    <article ng-repeat="item in items.list" class="item" ng-class="item.type">
        <div ng-include="'views/items/' + item.type + '-template.html'" class="inner"></div>
    </article>
</div>

// soundcloud-template.html
<soundcloud-music-item item="item"></soundcloud-music-item>

// the directive
myApp.directive 'soundcloudMusicItem', [ ->
    restrict: 'E'
    scope: 
        item: '='
    controller: 'soundcloudMusic'
    templateUrl: 'views/items/soundcloud-music-item.html'
    link: (scope, el, attr, ctrl) ->
]

What I'm trying to do is cut out having to load soundcloud-template.html altogether.

Was it helpful?

Solution

I don't have an angular app setup now, but did you try having a function return the generated template path in the directive based on the local $scope(which should be the item)?

// the directive
myApp.directive 'item', ['$scope', ($scope) ->
    restrict: 'E'
    scope: 
        item: '='
    templateUrl: -> return 'views/items/'+$scope.type+'-item.html'
    link: (scope, el, attr, ctrl) ->
]

The directive would be a general directive in this case called 'item' or so.

You can do the same with the controller, but my question is, do you really need a controller binded to a directive?

OTHER TIPS

Found a way to do what I was trying to do with React, including the same react code I had above, I saved the angular compile dependency and saved it to the angular body and called the react render like:

myApp.controller 'MainCtrl', ['$scope', 'fetcher', '$compile', ($scope, fetcher, $compile) ->
    $scope.$root.activeScope = $scope
    angular.$compile = $compile

    $scope.items = 
        list: []
        more: true

    fetcherCallback = (latest, callback) ->
        $scope.items.list = $scope.items.list.concat(latest)
        offset = $scope.items.list.length
        $scope.items.more = true
        callback(latest) if callback

        React.renderComponent feedRepeat(scope: $scope), document.getElementById('feedRepeat')

Then using the react iterator I called each template, and in each template after the template was mounted, I compiled the html based on given selector and passed in the new scope like:

/** @jsx React.DOM */

var MVItems = MVItems || {};

MVItems.soundcloud_favorite = React.createClass({

    componentDidMount: function () {
        // grab the selector
        this.selector = document.querySelector('[data-reactid="' + this._rootNodeID + '"]');

        // connect it with Angular's infrastructure so we can use the contollers
        angular.$compile(this.selector)(this.$scope);
    },

    render: function () {
        this.$scope = this.props.scope;

        var item = this.$scope.item;

        return (
            <html here....>
        )
    }
}

Then afterwards, any angular specific markup will be parsed in the componentDidMount method

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top