Jeff Rupert
Jeff Rupert

Reputation: 4840

Weird Angular2 Model Binding Issue

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:

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

Upvotes: 0

Views: 146

Answers (1)

Abdulrahman Alsoghayer
Abdulrahman Alsoghayer

Reputation: 16540

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.

Upvotes: 2

Related Questions