New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedded forms aren't attached to $scope #8403

Closed
metric152 opened this Issue Jul 29, 2014 · 3 comments

Comments

Projects
None yet
2 participants
@metric152

metric152 commented Jul 29, 2014

When a form is inside a ng-directive include it's not attached to the $scope object.

I go into detail about it here
http://blog.152.org/2014/07/angular-form-element-not-attaching-to.html

@caitp

This comment has been minimized.

Show comment
Hide comment
@caitp

caitp Jul 30, 2014

Contributor

So, the issue you're describing is really just a misunderstanding about the way scopes in Angular work. It's a bit of a tricky system and admittedly takes some getting used to, but this is working as expected.

ng-controller will create a new scope, as will ng-include whenever it adds a template to the DOM.

So what you end up with is a scope hierarchy like this:

  002 - rootScope
         003 - ngController
                004 - ngInclude

The included form directive adds createUser to the ngInclude scope (called 004 in the chart above, but the IDs in a real application won't necessarily match). You can't get at this via scope003.createUser, because it's lower in the scope hierarchy, you'd have to grab the child scope and get it that way (not recommended).

There are work arounds for this, for instance:

<div ng-controller="controllerName" ng-init="forms = {}; model = {}">
    <div ng-include=" 'path-to-the-template' "></div>
</div>

<!—- Inside path-to-the-template -—>
<form name="forms.createUser">
    <input name="name" ng-model="model.name" />
    <input name="email" ng-model="model.email" />
</form>

This will put the included form in scope003.forms.createUser, and will put the name and email inputs in scope003.model.name and scope003.model.email, respectively. Note, you don't necessarily have identifiers for scope003 declared, this is just indicating that it's in the controller's scope.

Here's an example: http://jsfiddle.net/g8DkL/

This might seem inconvenient, but it's really what you want to do anyways, so that you avoid confusion when new scopes are created that you aren't aware of.

So I don't think we're going to call this a bug, but it is clearly one of those hurdles that you need to jump over while learning the framework, and it is understandably frustrating =)

Contributor

caitp commented Jul 30, 2014

So, the issue you're describing is really just a misunderstanding about the way scopes in Angular work. It's a bit of a tricky system and admittedly takes some getting used to, but this is working as expected.

ng-controller will create a new scope, as will ng-include whenever it adds a template to the DOM.

So what you end up with is a scope hierarchy like this:

  002 - rootScope
         003 - ngController
                004 - ngInclude

The included form directive adds createUser to the ngInclude scope (called 004 in the chart above, but the IDs in a real application won't necessarily match). You can't get at this via scope003.createUser, because it's lower in the scope hierarchy, you'd have to grab the child scope and get it that way (not recommended).

There are work arounds for this, for instance:

<div ng-controller="controllerName" ng-init="forms = {}; model = {}">
    <div ng-include=" 'path-to-the-template' "></div>
</div>

<!—- Inside path-to-the-template -—>
<form name="forms.createUser">
    <input name="name" ng-model="model.name" />
    <input name="email" ng-model="model.email" />
</form>

This will put the included form in scope003.forms.createUser, and will put the name and email inputs in scope003.model.name and scope003.model.email, respectively. Note, you don't necessarily have identifiers for scope003 declared, this is just indicating that it's in the controller's scope.

Here's an example: http://jsfiddle.net/g8DkL/

This might seem inconvenient, but it's really what you want to do anyways, so that you avoid confusion when new scopes are created that you aren't aware of.

So I don't think we're going to call this a bug, but it is clearly one of those hurdles that you need to jump over while learning the framework, and it is understandably frustrating =)

@caitp

This comment has been minimized.

Show comment
Hide comment
@caitp

caitp Jul 30, 2014

Contributor

The reasons why this works this way make sense if you understand prototypical inheritance in javascript (child scopes prototypically inherit from their parent scopes, so scope004.proto === scope003, and scope003.proto === scope002, etc), so if it's unclear from this explanation and example, I suggest reading up on resources regarding that, including https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain

Contributor

caitp commented Jul 30, 2014

The reasons why this works this way make sense if you understand prototypical inheritance in javascript (child scopes prototypically inherit from their parent scopes, so scope004.proto === scope003, and scope003.proto === scope002, etc), so if it's unclear from this explanation and example, I suggest reading up on resources regarding that, including https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain

@metric152

This comment has been minimized.

Show comment
Hide comment
@metric152

metric152 Jul 30, 2014

Once you said the include will have its own scope my problem made complete sense. I didn't realize that was the case. Thank you so much for the help.

metric152 commented Jul 30, 2014

Once you said the include will have its own scope my problem made complete sense. I didn't realize that was the case. Thank you so much for the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment