0

I'm running into a place where the model binding on Angular2 is not binding as I expect, and I'm having problems determining where I went awry.

I have an array of objects as follows:

commands = [
    {
        "id": 2,
        "command": "!first",
        "action": "This is the first command. You found it!",
        "reply": false
    },
    {
       "id": 5,
        "command": "!hi",
        "action": "Hello, how are you today?",
        "reply": true
    },
    ...
];

The view template is as follows (clipped for brevity, only showing tags with relevant Angular2 info):

<form #commandForm="ngForm">
    <tr *ngFor="#cmd of commands">
        <td *ngIf=" ! isEditingCommand(cmd)">{{ cmd.command }}</td>
        <td *ngIf="isEditingCommand(cmd)">
            <input type="text" class="form-control" placeholder="!command" required [(ngModel)]="cmd.command" (ngModelChange)="cmd.command=cleanCommand($event)" ngControl="cmd" #cmd="ngForm">
        </td>
        <td *ngIf=" ! isEditingCommand(cmd)">{{ cmd.action }}</td>
        <td *ngIf="isEditingCommand(cmd)">
            <textarea class="form-control" rows="1" placeholder="Text to display." required [(ngModel)]="cmd.action" ngControl="action" #action="ngForm"></textarea>
        </td>
    </tr>
</form>

When isEditingCommand(cmd) === false, rows show up as follows:

State when not editing the command

When isEditingCommand(cmd) === true, this is what I get:

State when editing the command

I have changed both cmd and cmd.command to various names, in case command is a reserved word for Angular2, to no avail. When I put {{ cmd | json }} in the view, I receive this exception:

EXCEPTION: TypeError: Converting circular structure to JSON in [
                {{ cmd | json }}
             in CommandComponent@24:199]

I am unable to determine how this could have a circular structure, unfortunately. Even going through the Chrome Inspector I am not finding a place where it might be circular.

locals from Chrome Inspector

To assist, here are the functions that are defined in the view (TypeScript is giving me problems; I will refactor into it later):

CommandComponent.prototype.cleanCommand = function (value) {
    value = value.replace(/[^a-z]+/gi, '');
    if (0 >= value.indexOf('!') && '!' !== value.substr(0, 1)) {
        value = '!' + value;
    }

    return value;
};
CommandComponent.prototype.isEditingCommand = function (command) {
    if (null === this.currentCommand) {
        return false;
    }

    return this.editFormActive && this.currentCommand.id === command.id;
};
// These are not used by the template shown, but they set values used in the functions.
CommandComponent.prototype.editCommand = function (command) {
    this.editFormActive = true;
    this.currentCommand = command;
};
CommandComponent.prototype.cancelEditCommand = function () {
    this.editFormActive = false;
    this.currentCommand = null;
};

Environment:

  • Angular 2.0.0-beta.13
  • RxJS 5.0.0-beta.2
  • Zone.js 0.6.8

What did I do incorrectly? Let me know if more info is needed, thank you!

0

1 Answer 1

2

I am not sure I understood your issue correctly. But, I only see one problem that could cause some binding issues.

In this line:

<input type="text" class="form-control" placeholder="!command" required [(ngModel)]="cmd.command" (ngModelChange)="cmd.command=cleanCommand($event)" ngControl="cmd" #cmd="ngForm">

You redefined the local variable cmd. The first one, in the *ngFor="#cmd of commands". The other one #cmd="ngForm". So, the binding to cmd.command will be to cmd the ngForm not the #cmd of commands. In other words, You have added a new property command to ngForm.

This will explain the circular reference issue because ngForm is of type NgFormName which has a _parent reference.

Sign up to request clarification or add additional context in comments.

1 Comment

I... wow. Yeah, that makes a lot of sense. That would definitely cause a potential problem. And it most definitely fixed things. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.