ajax响应后更新UI

时间:2013-09-05 09:07:40

标签: javascript jquery ajax knockout.js

我是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);
    });

我的web方法由ajax请求调用如下:

// 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}}}

3 个答案:

答案 0 :(得分: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使您的属性通知视图其更改,以便视图可以相应更新。这应该有效但不完美,因为这是双向绑定,因此每当您更新div中的值时,视图模型对象都会立即更新 ,甚至如果您的ajax无法更新后端数据,则会使客户端和服务器端之间的数据不同步。

为了更好的解决方案。您需要查看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.update ajax成功功能中,触发更改:

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(); 
 }

更新 的 请务必将Product.Property的所有地点更改为Product.Property()以获取其属性值。例如:arr[i].Price应更改为arr[i].Price()

答案 1 :(得分: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的初始值为null,KO会完全删除此内容。 *注意:由于某种原因,我想到了@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.Product重命名为self.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));
});

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

答案 2 :(得分:-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反映。