Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
812 views
in Technique[技术] by (71.8m points)

rxjs - How to select a checkbox dynamically from an Observable in Angular

I am trying to create the following screen in Angular 8. I have a list of items (Item1 to Item4). A particular person inherits whether these items are turned on from their parent ("Inherited" column, which is not editable) but they can override these defaults by de/selecting checkboxes in the "Custom" column.

Mockup screenshot

When the page loads, I want both of these columns to be populated.

Here is the snippet of my template:

<tr *ngFor="let item of allitems">
    <td>{{ item.measure }}</td>
    <td>
        <input
            [value]="item.id"
            type="checkbox"
            [checked]="inheriteditems.indexOf(item.itemid) >= 0"
            disabled
        />
    </td>
    <td>
        <input
            [value]="item.itemid"
            type="checkbox"
            [checked]="itemIsChecked$(item.itemid) | async"
            (click)="onItemCheckChange($event)"
            name="item"
        />
    </td>
</tr>
<div *ngFor="let ci of customitems | async">{{ ci }}</div>

I have a service for managing the custom items:

@Injectable()
export class CustomItemService {
    private data: Array<string> = [];
    private _ciList = new Subject<Array<string>>();
    customItemList$ = this._ciList.asObservable();

    constructor() {
        this.notify();
    }

    loadList(res) {
        this.data = res;
        this.notify();
    }

    insert(id) {
        const ix = this.data.indexOf(id);

        if (ix === -1) {
            this.data.push(id);
            this.notify();
        }
    }

    remove(id) {
        const ix = this.data.indexOf(id);
        if (ix >= 0) {
            this.data.splice(ix, 1);
            this.notify();
        }
    }

    private notify() {
        this._ciList.next(this.data);
    }
}

and this is the component code:

@Component()
export class ItemEditComponent implements OnInit {

    allitems: Array<Item>;
    inheriteditems: Array<string>;
    customitems: Observable<Array<string>>;

    constructor(
        private service: CustomItemService,
    ) {

        this.allitems = [{
            id: "id1",
            name: "Item 1"
        }, {
            id: "id2",
            name: "Item 2"
        }, {
            id: "id3",
            name: "Item 3"
        }, {
            id: "id4",
            name: "Item 4"
        }];

        this.customitems = this.service.customItemList$;
        this.customitems.subscribe(res => console.log(res));
    }
    
    itemIsChecked$(id) {
        return this.customitems.pipe(
            map(res => {
                return res.indexOf(id);
            }),
        );
    }
    onItemCheckChange(event) {
        const cb = event.currentTarget;

        if (cb.checked) {
            this.service.insert(cb.value);
        } else if (!cb.checked) {
            this.service.remove(cb.value);
        }
    }
    
    ngOnInit() {
        this.inheriteditems = ["id1", "id2", "id3", "id4"];

        this.service.loadList(["id3"]);
    }
}

But as it stands, the Custom checkboxes are not selected on load, and the div at the end where I am dumping out the contents is empty. If I check one of the custom boxes, this populates.

I feel I'm missing something really obvious, but I can't spot it. Can someone point me int he right direction?

Thanks


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There is a lot of 'why' questions that I wanted to ask you. Anyway, I think that one of your problem is that ''itemIsChecked$'' not returning boolean.

Consider to return in 'itemIsChecked$' function at pipe map:

return res.indexOf(id) > -1;
        

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...