0

我是新手,knocokout.js所以我有一个表格,其中使用 ajax 调用绑定数据。当用户单击编辑按钮时,行信息会填充到表格下方同一页面上的表格中。在成功将数据更新到数据库的 ajax 调用之后,我无法显示已更改为表的特定对象的更改值。如果我刷新然后它显示新值。

这是我的 html 和 js 代码。

<div id="body">
        <h2>
            Knockout CRUD Operations with ASP.Net Form App</h2>
        <h3>
            List of Products</h3>
        <table id="products1">
            <thead>
                <tr>
                    <th>
                        ID
                    </th>
                    <th>
                        Name
                    </th>
                    <th>
                        Category
                    </th>
                    <th>
                        Price
                    </th>
                    <th>
                        Actions
                    </th>
                </tr>
            </thead>
            <tbody data-bind="foreach: Products">
                <tr>
                    <td data-bind="text: Id">
                    </td>
                    <td data-bind="text: Name">
                    </td>
                    <td data-bind="text: Category">
                    </td>
                    <td data-bind="text: formatCurrency(Price)">
                    </td>
                    <td>
                        <button data-bind="click: $root.edit">
                            Edit</button>
                        <button data-bind="click: $root.delete">
                            Delete</button>
                    </td>
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <td>
                    </td>
                    <td>
                    </td>
                    <td>
                        Total :
                    </td>
                    <td data-bind="text: formatCurrency($root.Total())">
                    </td>
                    <td>
                    </td>
                </tr>
            </tfoot>
        </table>
        <br />
        <div style="border-top: solid 2px #282828; width: 430px; height: 10px">
        </div>
        <div data-bind="if: Product">
            <div>
                <h2>
                    Update Product</h2>
            </div>
            <div>
                <label for="productId" data-bind="visible: false">
                    ID</label>
                <label data-bind="text: Product().Id, visible: false">
                </label>
            </div>
            <div>
                <label for="name">
                    Name</label>
                <input data-bind="value: Product().Name" type="text" title="Name" />
            </div>
            <div>
                <label for="category">
                    Category</label>
                <input data-bind="value: Product().Category" type="text" title="Category" />
            </div>
            <div>
                <label for="price">
                    Price</label>
                <input data-bind="value: Product().Price" type="text" title="Price" />
            </div>
            <br />
            <div>
                <button data-bind="click: $root.update">
                    Update</button>
                <button data-bind="click: $root.cancel">
                    Cancel</button>
            </div>
        </div>
</div>

代码

    function formatCurrency(value) {
        return "$" + parseFloat(value).toFixed(2);
    }

    function ProductViewModel() {

        //Make the self as 'this' reference
        var self = this;
        //Declare observable which will be bind with UI 
        self.Id = ko.observable("");
        self.Name = ko.observable("");
        self.Price = ko.observable("");
        self.Category = ko.observable("");

        var Product = {
            Id: self.Id,
            Name: self.Name,
            Price: self.Price,
            Category: self.Category
        };

        self.Product = ko.observable();
        self.Products = ko.observableArray(); // Contains the list of products

        // Initialize the view-model
        $.ajax({
            url: 'SProduct.aspx/GetAllProducts',
            cache: false,
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            data: {},
            success: function (data) {
                // debugger;

                $.each(data.d, function (index, prd) {

                    self.Products.push(prd);
                })
                //Put the response in ObservableArray
            }
        });

        // Calculate Total of Price After Initialization
        self.Total = ko.computed(function () {
            var sum = 0;
            var arr = self.Products();
            for (var i = 0; i < arr.length; i++) {
                sum += arr[i].Price;
            }
            return sum;
        });


        // Edit product details
        self.edit = function (Product) {
            self.Product(Product);

        }

        // Update product details
        self.update = function () {
            var Product = self.Product();

            $.ajax({
                url: 'SProduct.aspx/Update',
                cache: false,
                type: 'POST',
                contentType: 'application/json; charset=utf-8',
                data: "{Product:" + ko.toJSON(Product) + "}",
                success: function (data) {
                      console.log(data.d);                        
                      self.Product(null);

                    alert("Record Updated Successfully");
                },
                error: function (data) {
                    console.log(data);
                }
            })

        }



        // Cancel product details
        self.cancel = function () {
            self.Product(null);

        }
    }

    $(document).ready(function () {
        var viewModel = new ProductViewModel();
        ko.applyBindings(viewModel);
    });

由ajax请求调用的我的webmethod如下:

// to update product
    [WebMethod]
    public static testModel.Product Update(testModel.Product Product)
    {
        testEntities db = new testEntities();
        var obj = db.Products.First(o => o.Id == Product.Id);
        obj.Name = Product.Name;
        obj.Price = Product.Price;
        obj.Category = Product.Category;

        db.SaveChanges();


        return obj;
    }

ajax调用的JSON响应如下

{"d":{"__type":"testModel.Product","Id":31,"Name":"12","Category":"12","Price":1350,"EntityState":2,"EntityKey":
{"EntitySetName":"Products","EntityContainerName":"testEntities","EntityKeyValues":
[{"Key":"Id","Value":31}],"IsTemporary":false}}}
4

3 回答 3

0

有一点要改变:

代替

$.each(data.d, function (index, prd) {
     self.Products.push(prd);
 })

和:

$.each(data.d, function (index, prd) {
     self.Products.push({
                    Id: ko.observable(prd.Id),
                    Name: ko.observable(prd.Name),
                    Price: ko.observable(prd.Price),
                    Category: ko.observable(prd.Category)
                });
})

用于ko.observable使您的属性通知视图其更改,以便视图可以相应地更新。这应该可以工作,但并不完美,因为这是 2 路绑定,所以每当您div更新.端和服务器端。

为了更好的解决方案。你需要看看protectedObservable

$.each(data.d, function (index, prd) {
         self.Products.push({
                        Id: ko.protectedObservable(prd.Id),
                        Name: ko.protectedObservable(prd.Name),
                        Price: ko.protectedObservable(prd.Price),
                        Category: ko.protectedObservable(prd.Category)
                    });
    })

在您的self.updateajax 成功函数中,触发更改:

success: function (data) {
    var product =self.Product();   
    product.Id.commit();
    product.Name.commit();
    product.Price.commit();
    product.Category.commit();     
    self.Product(null);

    alert("Record Updated Successfully");
}

如果有错误则恢复:

error: function (data) {
    product.Id.reset();
    product.Name.reset();
    product.Price.reset();
    product.Category.reset(); 
 }

更新: 记得用 to 更改所有地方Product.PropertyProduct.Property()获取其属性值。例如: arr[i].Price应该改为arr[i].Price()

于 2013-09-05T09:25:09.403 回答
0

这是正在发生的事情。这里:self.Products.push(prd)prd 只是一个具有普通属性值的普通 javascript 对象,没有什么是可观察的。您将原始对象推送到 Products observableArray 上,这会更新 DOM,因为 Products 已更改并且 KO 正在监视它。当您单击“编辑”时,您设置self.Product为该普通对象,并且 KO 使用该对象及其值更新 DOM,因为 Product 已更改并且 KO 正在监视它。所以现在您的产品表单显示在下面,您会看到信息,并且看起来您可以编辑属性,但 KO 不会更新这些属性更改,因为 KO 没有观察它们。它们是不可观察的。改变:

$.each(data.d, function (index, prd) {
  //self.Products.push(prd);
  self.Products.push({
    Id: ko.observable(prd.Id),
    Name: ko.observable(prd.Name),
    Price: ko.observable(prd.Price),
    Category: ko.observable(prd.Category)
  });
});



一般有用的提示



<div data-bind="if: Product">

当您使用 ko.applyBindings 将 viewModel 绑定到 DOM 时,这只计算一次。由于self.Product具有nullKO 的初始值,因此完全消除了这一点。*注意:出于某种原因,我在考虑@if。

这与可见绑定类似,但当值为 false 时,元素及其子元素将从 DOM 中删除。所以有比必要的更多的 DOM 操作。你可能只是想隐藏这个<div>

我建议将其更改为:

<div data-bind="visible: Product"> 

而不是这个:

<input type="text" data-bind="text: Product().Name" />
<input type="text" data-bind="text: Product().Category" />
<input type="text" data-bind="text: Product().Price" />

试试这个:

<div data-bind="with: Product">
  <input type="text" data-bind="text: Name" />
  <input type="text" data-bind="text: Category" />
  <input type="text" data-bind="text: Price" />
</div>

考虑重命名self.Productself.SelectedProduct使其更清楚它的用途。


我不确定这在 ViewModel 中做了什么:

//Declare observable which will be bind with UI 
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");

var Product = {
    Id: self.Id,
    Name: self.Name,
    Price: self.Price,
    Category: self.Category
};

您不会在 DOM 中使用它们。不过,您在这方面走在了正确的道路上。相反,在 ProductViewModel 之前,创建这个:

function ProductModel(data) {
  var self = this;
  data = data || {};
  self.Id = ko.observable(data.Id);
  self.Name = ko.observable(data.Name);
  self.Price = ko.observable(data.Price);
  self.Category = ko.observable(data.Category);
}

现在代替:

$.each(data.d, function (index, prd) {
  self.Products.push({
    Id: ko.observable(prd.Id),
    Name: ko.observable(prd.Name),
    Price: ko.observable(prd.Price),
    Category: ko.observable(prd.Category)
  });
});

我们可以这样做:

$.each(data.d, function (index, prd) {
  self.Products.push(new ProductModel(prd));
});

希望这会让你朝着正确的方向前进。

于 2013-09-05T10:17:58.690 回答
-1

添加self.Products.push(data.d);update()函数success处理程序。

success: function (data) {
     console.log(data.d);                        
     self.Product(null);

     self.Products.push(data.d);

     alert("Record Updated Successfully");
},

您需要更新数组,以便它反映在绑定的 html 中。

于 2013-09-05T09:26:21.130 回答