Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I am trying to mix Angular and React.JS. You can see my code here. Most examples I have seen involve an input written in basic Angular, and then output written in React like in this example. I am trying to do the opposite. I have two input fields as React components created in a directive and then an output of the model done with Angular.

I cannot get the output to reflect changes in the model. The model being $scope.formData = {name: "name", email: "email"};

I tried to follow the example in this video, and create an isolated scope in the directive

scope: {
            formname: '=formname',
            formemail:'=formemail'
        },

and then pass the proper values through to the React template. It doesn't seem to have any affect. My input is not connected to the formData. In my non-React version of this, the model data fills in the input immediately and the output reflects changes to the input.

Because binding that data in an Angular style is breaking, I tried to have the React components update the model in a more Reactish way. I wrote a function in the controller called update_model,

$scope.update_model = function(data_type, updated_data){
                $scope.$apply(function() {
                    $scope.formData[data_type] = updated_data;
                });
                console.log($scope.formData);
            }

I then passed that function through the directive to the React template using scope.update_model, in the link function.

link: function(scope, element) {
        React.renderComponent(Form_Profile_Component({update_model: scope.update_model, name_label: 'name', email_label: 'email', name_data: scope.formname, email_data: scope.formemail}), element[0]);
    }

Now in the template, the input elements have and onChange event detector that will call this, and update the Model. The Model is supposed to be displayed at the bottom of the page with

    <pre>
        {{ formData }}
    </pre>

The console.log shows a change in formData, but the {{formData}} display does not change.

Why won't my display {{formData}} show what is going on in the actual formData object?

EDIT: Just to make sure there wasn't a problem with {formData} I threw <input ng-model="formData.name"> in a few places in form.html, and there was no problem. The two way binding worked there.

EDIT 2: I tried adding the code below to the directive.

link: function(scope, element) {
            scope.$watch('formData.name', function(newVal, oldVal) {
              console.log("---");
              React.renderComponent(Form_Profile_Component({update_model: scope.update_model, name_label: 'name', email_label: 'email', name_data: scope.formData.name, email_data: scope.formData.email}), element[0]);
            });
        }

I believe that when there is a change in formData, it will call this function and update the React component, or at the very least print '---' to the console. When I use the React input or the proper input nothing happens, which is not so surprising at this point. But when I tried the working input from the first edit, which does alter {{formData}}, nothing happens. It doesn't trigger the watch at all, I don't understand why.

share|improve this question
    
It would be useful if you could post your full code in context. I'm not sure if I understand how your tree of directives are set up. – August Lilleaas Jun 24 '14 at 11:36
    
All the code is in a Plunker which I linked at the top. The main app is in index.html, then form.html is inserted into that. app.js has the router, controller, and the directive. form-profile.js is the React template. – EasilyBaffled Jun 24 '14 at 11:39
    
Ah, sorry, I didn't see that link. Checking it out now :) – August Lilleaas Jun 24 '14 at 11:39
up vote 2 down vote accepted

You're on the right track with your 2nd edit where you put the renderComponent call inside a scope.$watch. This will make sure that the react component is re-rendered every time your watch variable formData.name changes.

However if you're looking for the changes you make within your React Component to propagate back out to angular, you need to make sure that the callback function you're passing to react has scope.$apply() call in it. Either encapsulating the change, or just after it.

Here's a quick example:

In your controller:

$scope.myVar  = 'foo';
$scope.setVar = function(value) {
    $scope.myVar = value;
    $scope.$apply();
};

In your directive's link function (assuming no restricted scope, else change name as needed)

scope.$watch('myVar', function() {
    React.renderComponent(
        MyComponent({
            myVar:  scope.myVar,
            setVar: scope.setVar
        }),
        element.get(0)
    );
});

Then just call the this.props.setVar function from within your react component with the new value and it'll update correctly on the model.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.