使用knockoutjs操纵视图模型

时间:2013-12-09 09:06:30

标签: javascript asp.net asp.net-mvc asp.net-mvc-4 knockout.js

如何使用KnockoutJS创建函数,我可以调用它来对视图模型进行一些操作?

型号:

public class ViewModel
{
   public int User { get; set; }
   public string Address { get; set; }
   public string ZipCode { get; set; }
   public List<Product> Products { get; set; }

}

public class Product
{
   public int Id { get; set; }
   public string Name { get; set; } 
}

使用Javascript:

<script type="text/javascript">
        var Product = function (Id, Name) {
            self = this;
            self.Id = Id;
            self.Name = Name;
        }

        function Add() {
            viewModel.products.push(new Product(2, "bread"));
        }

        function Remove(product) {
            viewModel.products.remove(product);
        }

        var viewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)));
        viewModel.products = ko.observableArray();

        ko.applyBindings(viewModel);

        Add();
        console.log(viewModel.products().length);

        var t = new Product(2, "bread");

        Remove(t);
        console.log(viewModel.products().length);
</script>

在此处添加此类作品,但function Remove(product)不会从array中删除该产品。我没有收到错误,console只打印出1(在viewModel.products().length次调用中)。

那么如何为KnockoutJS创建适当的函数才能在页面的任何位置调用它们?

2 个答案:

答案 0 :(得分:3)

我看不到你的代码有什么明显的东西,它不像你的模型中返回的对象,你的删除实际上是在工作,但剩下的对象是从模型返回的对象?

我更喜欢在从模型中读回对象时映射对象,以避免像这样创建匿名对象:

var mapping = {
    'Products': {
        create: function(options) {
            return new Product(options.data.Id, options.data.Name);
        }
    }
}

这可确保您的产品是实际的产品对象。

您还可以检查从模型返回的json是这样的:

{ "User": "a", "Address": "b", "ZipCode": "zip", "Products":[{"Id":1,"Name":"jam"}]};

以下是在jsFiddle中工作的完整代码(检查控制台的输出):

http://jsfiddle.net/6qsjz/15/

这显示,一个从模型返回,一个添加然后删除,一个产品在集合中。

<强>更新

您可以通过将模型更改为此来初始化集合服务器端:

public class ViewModel
{
    public ViewModel()
    {
        Products = new List<Product>();
    }
    public int User { get; set; }
    public string Address { get; set; }
    public string ZipCode { get; set; }
    public List<Product> Products { get; set; }

}

这意味着如果您采用上述方法,则无需执行viewModel.products = ko.observableArray();

<强>更新

然后你可以重构它以使它给它更好的结构(更模块化):

  var Product = function (Id, Name) {
        self = this;
        self.Id = Id;
        self.Name = Name;
    }

    var mapping = {
        'Products': {
            create: function(options) {
                return new Product(options.data.Id, options.data.Name);
            }
        }
    }   


function ProductsViewModel(data) {
    var self = this;   
    ko.mapping.fromJS(data, mapping, self);

     self.Add = function Add(product) {
         self.Products.push(product);
     }

     self.Remove = function Remove(product) {
         self.Products.remove(product);
     }
}


var data = { "User": "a", "Address": "b", "ZipCode": "zip", "Products":[{"Id":1,"Name":"jam"}]};

    var viewModel = new ProductsViewModel(data);
    ko.applyBindings(viewModel);

    // add
    var product = new Product(2, "bread");
    viewModel.Add(product);
    console.log(viewModel.Products()); 

    // remove
    viewModel.Remove(product);
    console.log(viewModel.Products());

更新了小提琴(再次查看输出控制台):

http://jsfiddle.net/6qsjz/16/

答案 1 :(得分:2)

    var t = new Product(2, "bread");

这会创建一个全新的对象。

    Remove(t);

由于t是全新的,viewmodel.products中不存在(即使具有相同成员的完全不同的对象),因此remove之后不会删除任何内容observableArray的方法如果传递了对象,则使用对象标识。

您可以将Remove重写为

    function Remove(product) {
        viewModel.products.remove(function(item) {
          return item.Id==product.Id;
        }); 
    }

因为将函数传递给remove方法会导致它删除函数为true的所有项。

您的Product构造函数中也存在问题:

    var Product = function (Id, Name) {
        self = this;

self在这里是全球性的,出于某些棘手的原因,它实际上是window的别名。使用var进行前缀。