Can't access form on $scope

Has anyone been able to access a form from their controller? I can setup a small project using just angular that has this code:

<form name="testFormName">
    ....
</form>

and from my controller I can access: $scope.testFormName.$dirty

When I try this same thing in my Ionic app, I don’t have access to testFormName on my scope. Logging shows that $scope.testFormName is undefined.

Any ideas?

Don’t have any trouble accessing the form controller inside controllers. You have a sample?

Sure, here is my HTML:

<view>
    <content has-header="true" has-footer="true" padding="false">
        <form name="playerForm">
            <div class="list">
                <label class="item item-input item-stacked-label">
                    <span class="input-label">Player Name</span>
                    <input type="text" name="playerName" ng-model="player.Name">
                </label>
            </div>
        </form>
    </content>
    <div class="bar bar-footer bar-gray">
        <div class="button-bar">
            <a class="button button-positive button-bold" ng-click="onSavePlayer()">Save Player</a>
        </div>
    </div>
</view>

Here is my route:

.state('ManagePlayer', {
     url: 'ManagePlayer/?playerId',
     templateUrl: 'views/ManagePlayer.html',
     controller: 'ManagePlayerController'
});

Now I just try to access the form via $scope.playerForm from my ManagePlayerController and it is undefined.

As you can see I have a button which has an ng-click="onSavePlayer()" and that is getting called fine.

Looks like I’ve got it working now: I had to make the <form> element the first child in my <view> element. Must be that the <content> directive is messing with the scope?

Here is what I did in case anyone else has this issue:

<view>
    <form name="playerForm">
        <content>
            ...
        </content
    </form>
</view>
2 Likes

Shouldn’t have had an impact, but it’s something I’ll look into. Glad it’s working now!

@DiscGolfer17 & @max Actually, I have just discovered this same problem. Previously, I was using forms inside directives. Now that I have a form that is on a route, I can’t access the form Controller in $scope.

As mentioned, if the form is the first element of the route, it is accessible from the controller. Otherwise, it does not exist.

See this Plunker : http://plnkr.co/edit/rSwAAm1Eok4nvQ82XZih

Open the console and switch between pages. If you open up the logged scopes, you’ll see the Home Page scope has no property ‘userForm’. the About page scope does have ‘userForm’.

FYI : There is another “fix” for this. It’s not pretty, but it works.

See this new Plunker : http://plnkr.co/edit/pIyk0KPzLFn5gKMJpLh5

I’ve created a new controller and associated it with the form on the Home page. Now, that controller’s scope can access the form.

I’m also noticing some scope variables that shouldn’t be on the Home Page scope, like leftButtons, navTitle, rightButtons, and scrollView. Made an issue here: https://github.com/driftyco/ionic/issues/483

@max Those scope variables are there because I set them in the controller. I don’t think that’s a problem. Or am I doing something completely wrong?

Oh, you’re right, my bad. Thanks for pointing that out :slight_smile:

I think I’m seeing a different but related problem. After upgrading to 0.9.21 from 0.9.19 my scope variables when accessed from a controller are always undefined.

A test case is here: http://plnkr.co/edit/u8D1C1pPFR9spJiSYXSj

Type a phone number into the phone number text box. Notice that the two way binding works since whatever you enter is repeated below the button. However, when you hit the “login” button, it prints out $scope.phoneNumber and it appears to be undefined. Not sure what’s wrong because this used to work correctly when I was using 0.9.19. Any help would be appreciated! Thanks!

@superabuh I am seeing this as well. Any changes to an <input ... ng-model="scopeVar" /> are not being updated on the $scope.

Any ideas about this @max?

Thanks for the test case @superabuh, let me look into this and see if I can narrow it down. Hustle hustle hustle :slight_smile:

I think the problem has to do with how Angular creates a new scope for directives that request an isolated scope. I was able to get this to work if I initialize my scope variable as an object:

.controller('testController', function($scope) {
    // This will not be updated
    $scope.testVar = '';

    // This will be updated
    $scope.otherTestVar = { value: '' };
});

Because <content> is a directive with an isolated scope, it will lose the reference to $scope.testVar but not $scope.otherTestVar because it is an object.

Here is my test HTML:

<content>
    <input type="text" ng-model="testVar" />
    <input type="text" ng-model="otherTestVar.value" />
</content>

@max Is this something you guys can handle, or is this Angular specific?

4 Likes

@max and @superabuh Looks like this is expected behavior in Angular. See this article explaining scope.

I guess the reason I’ve never seen this before is because I always bind to models (objects) rather than primitives. Good to know in the future though!

Ah yes, this one comes up constantly, good catch. It’s really an angular issue/nuance and is not something we can or will have anything to say about.

@DiscGolfer17 and @max thanks for the help! I’ve updated the test case so that it’s properly working. Maybe it’ll help someone else who has the same issue!

One thing I had to do that was unexpected was to initialize my models in the controller like so:

$scope.userInput = {};

Before I didn’t have to do this. Makes sense why this is required after reading the article @DiscGolfer17 linked to.

Maybe I’m missing something, but I think this conversation departed from the original point. The original point was that the FORM controller is not accessible from the scope in the controller.

Yes, $scope inheritance is a common cause of problems with user variables. And yes, initializing as Objects helps solve this frequently. But doing this still doesn’t allow the controller to access the form.

See this updated Plunker. http://plnkr.co/edit/9PIjGgQWKKSkf3pyJw5

From the HomeController, even after initializing the “member” object, the “userForm” is still not visible. Is this simply a matter of inheritance as well? Is the only solution is to have controllers tied to content beyond the route controller or to put all logic in directive controllers?

3 Likes

@Calendee Yeah we kinda diverted there for a bit haha…

I believe the issue with the form not being visible is actually correct, and expected as well. When Angular creates the isolated scope for the directive, because it is using ng-transclude, it will actually create a new child scope for the transcluded content. This new scope does not prototypically inherit from it’s parent, thus it’s not available on $scope.

One way to get around this is to use $parent. This will tell Angular to look to the parent scope for the property userForm:

<content>
    <form name="$parent.userForm">
        <input type="text" name="givenName" placeholder="First Name" ng-model="member.givenName" />
    </form>
</content>

If you try that, you will now be able to access $scope.userForm from within your controller.

7 Likes

@DiscGolfer17 I knew about $parent, but never knew it might be needed to identify the form controller. You are absolutely right though. Thanks.

Updated Example : http://plnkr.co/edit/0Ht8vOJyGoPw8a0AOsDB