淘汰赛:从 Observable 数组中删除特定项目

Knockout: Removing Specific Item from Observable Array

我正在尝试通过制作一个简单的游戏列表来自学 Knockout.js 可以添加和删除的游戏。目前我坚持从可观察数组中删除特定项目。我有一系列游戏,我将它绑定到一个 div 上,其中列出了每个游戏的标题、类型、平台等。每个游戏我也有一个删除按钮,但它们不起作用。我的设置与 Knockout 文档中的完全一样:

https://knockoutjs.com/documentation/click-binding.html

我在这里也发现了其他人遇到完全相同的问题:

Remove items from Knockout observable array

但是,列出的拼接解决方案对我不起作用。这次函数确实触发了,但它没有从数组中删除正确的项目,而是删除了数组中的最后一项,而不管单击了哪个删除按钮。我不知道为什么 Knockout 文档中的代码不起作用,以及拼接解决方案为什么不能正常工作。这是我的代码。请原谅所有硬编码值。我只是想让它的基础知识在此刻工作。

@{
    ViewBag.Title = "My Game List";
}

<head>
    <script type="text/javascript">
        $(function () {
            var game1 = ko.observable({
                title: 'Bioshock',
                genre: 'Shooter',
                platform: 'XBox 360',
                releaseDate: '8/21/2007',
                developer: 'Irrational Games',
                publisher: '2K Games',
                imageURL: 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/BioShock_cover.jpg/220px-BioShock_cover.jpg'
            });
            var game2 = ko.observable({
                title: 'The Legend of Zelda: Ocarina of Time',
                genre: 'RPG',
                platform: 'N64',
                releaseDate: '11/21/1998',
                developer: 'Nintendo',
                publisher: 'Nintendo',
                imageURL: 'https://cdn-images-1.medium.com/max/1600/1*n2iccNMASW983gg-ZmMdTw.jpeg'
            });
            var game3 = ko.observable({
                title: 'Devil May Cry',
                genre: 'Hack-n-Slash',
                platform: 'PS2',
                releaseDate: '8/23/2001',
                developer: 'Capcom',
                publisher: 'Capcom',
                imageURL: 'https://upload.wikimedia.org/wikipedia/en/thumb/1/1e/DMC1FrontCover.jpg/220px-DMC1FrontCover.jpg'
            });
            var game4 = ko.observable({
                title: 'Comix Zone',
                genre: 'Beat-em-Up',
                platform: 'Sega Genesis',
                releaseDate: '8/2/1995',
                developer: 'Sega',
                publisher: 'Sega',
                imageURL: 'https://upload.wikimedia.org/wikipedia/en/thumb/0/0e/Comix_Zone_Coverart.png/220px-Comix_Zone_Coverart.png'
            });
            var game5 = ko.observable({
                title: 'To the Moon',
                genre: 'Visual Novel',
                platform: 'PC',
                releaseDate: '9/1/2011',
                developer: 'Freebird Games',
                publisher: 'Freebird Games',
                imageURL: 'https://steamcdn-a.akamaihd.net/steam/apps/206440/capsule_616x353.jpg?t=1519836062'
            });
            function gamesViewModel() {
                var self = this;
                self.gamesList = ko.observableArray([game1, game2, game3, game4, game5]);
                self.gameToAdd = ko.observable({
                    title: 'Mass Effect',
                    genre: 'RPG',
                    platform: 'PC',
                    releaseDate: '11/20/2007',
                    developer: 'BioWare',
                    publisher: 'EA',
                    imageURL: 'https://steamcdn-a.akamaihd.net/steam/apps/17460/header.jpg?t=1447351599'
                });
                self.addGame = function () {
                    self.gamesList.push(self.gameToAdd);
                };
                self.removeGame = function (gameToRemove) {
                    self.gamesList.remove(gameToRemove);
                    //var gameIndex = self.gamesList.indexOf(gameToRemove);
                    //self.gamesList.splice(gameIndex, 1);
                };
            }
            ko.applyBindings(new gamesViewModel);
        });

    </script>
</head>
<div class="jumbotron">
    <h1>TOP 5 GAMES</h1>
</div>

<div class="row">
    <h4>Games</h4>
    <div class="card-columns" data-bind="foreach: gamesList">
        <div class="card">
            <a data-bind="attr: {href: imageURL}" target="_blank">
                <img class="card-img-top" data-bind="attr: {src: imageURL}" />
            </a>
            <div class="card-body">
                <h5 class="card-title" data-bind="text: title"></h5>
                <div class="card-text">
                    <div>
                        <span>Genre: </span>
                        <span data-bind="text: genre" />
                    </div>
                    <div>
                        <span>Platform: </span>
                        <span data-bind="text: platform" />
                    </div>
                    <div>
                        <span>Release Date: </span>
                        <span data-bind="text: releaseDate" />
                    </div>
                    <div>
                        <span>Developer: </span>
                        <span data-bind="text: developer" />
                    </div>
                    <div>
                        <span>Publisher: </span>
                        <span data-bind="text: publisher" />
                    </div>
                </div>
                <button class="btn btn-danger" data-bind="click: $parent.removeGame">-Remove</button>
            </div>
        </div>
    </div>
    <button data-bind="click: addGame">+Add</button>
</div>

Using "()" in knockoutjs is very tricky. Your code is perfect but here is the problem. game objects (game1, game2, ... ) are declared as observable (i would keep them as normal variable) and you are pushing observable reference in gamesList not actual values. Thats why remove method is not able to identify it.

要么声明没有可观察对象的游戏对象,要么在列表中用“()”分配它们。

 $(function () {
            var game1 = ko.observable({
                title: 'Bioshock',
                genre: 'Shooter',
                platform: 'XBox 360',
                releaseDate: '8/21/2007',
                developer: 'Irrational Games',
                publisher: '2K Games',
                imageURL: 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/BioShock_cover.jpg/220px-BioShock_cover.jpg'
            });
            var game2 = ko.observable({
                title: 'The Legend of Zelda: Ocarina of Time',
                genre: 'RPG',
                platform: 'N64',
                releaseDate: '11/21/1998',
                developer: 'Nintendo',
                publisher: 'Nintendo',
                imageURL: 'https://cdn-images-1.medium.com/max/1600/1*n2iccNMASW983gg-ZmMdTw.jpeg'
            });
            var game3 = ko.observable({
                title: 'Devil May Cry',
                genre: 'Hack-n-Slash',
                platform: 'PS2',
                releaseDate: '8/23/2001',
                developer: 'Capcom',
                publisher: 'Capcom',
                imageURL: 'https://upload.wikimedia.org/wikipedia/en/thumb/1/1e/DMC1FrontCover.jpg/220px-DMC1FrontCover.jpg'
            });
            var game4 = ko.observable({
                title: 'Comix Zone',
                genre: 'Beat-em-Up',
                platform: 'Sega Genesis',
                releaseDate: '8/2/1995',
                developer: 'Sega',
                publisher: 'Sega',
                imageURL: 'https://upload.wikimedia.org/wikipedia/en/thumb/0/0e/Comix_Zone_Coverart.png/220px-Comix_Zone_Coverart.png'
            });
            var game5 = ko.observable({
                title: 'To the Moon',
                genre: 'Visual Novel',
                platform: 'PC',
                releaseDate: '9/1/2011',
                developer: 'Freebird Games',
                publisher: 'Freebird Games',
                imageURL: 'https://steamcdn-a.akamaihd.net/steam/apps/206440/capsule_616x353.jpg?t=1519836062'
            });
            function gamesViewModel() {
                var self = this;
                self.gamesList = ko.observableArray([game1(), game2(), game3(), game4(), game5()]);
                self.gameToAdd = ko.observable({
                    title: 'Mass Effect',
                    genre: 'RPG',
                    platform: 'PC',
                    releaseDate: '11/20/2007',
                    developer: 'BioWare',
                    publisher: 'EA',
                    imageURL: 'https://steamcdn-a.akamaihd.net/steam/apps/17460/header.jpg?t=1447351599'
                });
                self.addGame = function () {
                    self.gamesList.push(self.gameToAdd);
                };
                self.removeGame = function (gameToRemove) {
                    self.gamesList.remove(gameToRemove);
                    //var gameIndex = self.gamesList.indexOf(gameToRemove);
                    //self.gamesList.splice(gameIndex, 1);
                };
            }
            ko.applyBindings(new gamesViewModel);
        });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="jumbotron">
    <h1>TOP 5 GAMES</h1>
</div>

<div class="row">
    <h4>Games</h4>
    <div class="card-columns" data-bind="foreach: gamesList">
        <div class="card">
            <a data-bind="attr: {href: imageURL}" target="_blank">
                <img class="card-img-top" data-bind="attr: {src: imageURL}" />
            </a>
            <div class="card-body">
                <h5 class="card-title" data-bind="text: title"></h5>
                <div class="card-text">
                    <div>
                        <span>Genre: </span>
                        <span data-bind="text: genre" />
                    </div>
                    <div>
                        <span>Platform: </span>
                        <span data-bind="text: platform" />
                    </div>
                    <div>
                        <span>Release Date: </span>
                        <span data-bind="text: releaseDate" />
                    </div>
                    <div>
                        <span>Developer: </span>
                        <span data-bind="text: developer" />
                    </div>
                    <div>
                        <span>Publisher: </span>
                        <span data-bind="text: publisher" />
                    </div>
                </div>
                <button class="btn btn-danger" data-bind="click: $parent.removeGame">-Remove</button>
            </div>
        </div>
    </div>
    <button data-bind="click: addGame">+Add</button>
</div>