简体   繁体   中英

jaydata 1.5 with odata 4 and angularjs - errors when saving / updating data

I am using jaydata 1.5.1 with odata 4 and ASP.Net WebAPI OData 4. Unfortunately almost all of the examples on the jaydata website are for older versions of jaydata itself or odata protocols < 4.0. I couldn't find any suitable example that covers jaydata > 1.5 + odata 4 + angularjs which makes me at least feel that this project (jaydata) is kind of dying.

I managed to init the jaydata service and to request data. But as soon as I am trying to manipulate data (adding, editing, saving) I am getting errors I can not resolve due to a lack of documentation. Please find here the code I have so far:

index.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Cache-Control" content="no-store" />
<meta charset="utf-8" />

<link href="Content/bootstrap.min.css" rel="stylesheet" />
<link href="css/font-awesome.min.css" rel="stylesheet" />
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Scripts/odatajs-4.0.0/odatajs-4.0.0.min.js"></script>

<script src="Scripts/angular.min.js"></script>

<script src="Scripts/jaydata/jaydata.js"></script>
<script src="Scripts/jaydata/jaydatamodules/angular.min.js"></script>
<!--<script src="Scripts/jaydata/jaydataproviders/oDataProvider.min.js"></script>-->
<!--<script src="app/model.js"></script>-->

<script src="app/app.js"></script>

</head>
<body data-ng-app="app">

<div ng-controller="ItemController">
    <ul>
        <li ng-repeat="item in Items">
            <input id="checkSlave" type="checkbox" ng-model="item .IstAktiv">
            {{item .Vorname}} {{item .Name}} ({{item .Klinik}} - {{item .Abteilung}} : {{item .Station}})
        </li>
    </ul>
        <button ng-click="newItem()">add new</button>
    <p>
        <form ng-if="selectedItem">
            <fieldset style="width: 300px; background-color: #0094ff;">
                <legend>{{selectedItem.Name}}</legend>
                <br />
                <label>
                    <table class="table table-striped table-bordered table-condensed">
                        <thead>
                            <tr>
                                <td class="text-center">Aktiv</td>
                                <td class="text-center">Vorname</td>
                                <td class="text-center">Name</td>
                                <td class="text-center">Klinik</td>
                                <td class="text-center">Abteilung</td>
                                <td class="text-center">Station</td>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td class="text-center"><input id="checkSlave" type="checkbox" ng-model="selectedItem.IstAktiv"></td>
                                <td class="text-center"><input ng-model="selectedItem.Vorname" size="20" /></td>
                                <td class="text-center"><input ng-model="selectedItem.Name" size="20" /></td>
                                <td class="text-center"><input ng-model="selectedItem.Klinik" size="20" /></td>
                                <td class="text-center"><input ng-model="selectedItem.Abteilung" size="20" /></td>
                                <td class="text-center"><input ng-model="selectedItem.Station" size="20" /></td>

                            </tr>
                        </tbody>
                    </table>
                </label>
                    <button ng-click="save()">Save</button>
                    <button ng-click="remove()">Remove</button>
</fieldset>
        </form>
    </p>
</div>
</body>
</html>

app.js:

var app = angular.module('app', ['jaydata']);

app.controller('ItemController', ['$scope', '$data', function ($scope, $data, $q) {
    $scope.Items = [];
    $scope.selectedItem = null;

    $data.initService('http://odata/test/JaydataTest/')
        .then(function (context) {
            $scope.context = context;
            context
                .Items
                //.map(function (p) { return p.Name })
                //.select("{ CategoryObject: it.Category, Name: it.Name }")
                //.filter(function (item) {  item.Name.startsWith('Kim');})
                // .filter(function (product) { return product.Id > idParam }, { idParam: 2 })
                //.find(2)
                //.orderBy(function (item) {item.Klinik})
                .toArray()
                .then(function (result) {
                    $scope.Items = result;
                    $scope.$apply();
                })
        })
        .catch(function (error) {
            alert(error);
        });

    $scope.save = function () {
        if ($scope.selectedItem.ItemId) {
            // save existing
            $scope.context.Items.attach($scope.selectedItem, true);
            $scope.selectedItem.entityState = $data.EntityState.Modified;
        }
        else {
            // save new
            $scope.context.Items.add($scope.selectedItem, true);
        }
        $scope.saveChanges();
    };

    $scope.saveChanges = function () {

        $scope.context.saveChanges()
            .then(function (n) {
                $scope.selectedItem = null;
                $scope.$apply();
            })
            .fail(function (error) { console.log(error); });
    }

    $scope.newItem = function () {
        var ctx = $scope.context;
        $scope.selectedItem = new ctx.Items.elementType({Name: "new Item"})
    };
}])

I get the following errors:

1) when saving, data is saved correctly to the underlying database but I get the follwing console error and the context is not getting updated and the new item doesn't show up only after refreshing the page (angular.js = jaydatamodules/angular.js):

TypeError: n.call(...).then(...).fail is not a function
    at Container.a.default.EntityContext.saveChanges (angular.js:266)
    at n.$scope.saveChanges (app.js:112)
    at n.$scope.save (app.js:91)
    at fn (eval at <anonymous> (angular.js:14432), <anonymous>:4:203)
    at b (angular.js:15485)
    at e (angular.js:25018)
    at n.$eval (angular.js:17229)
    at n.$apply (angular.js:17329)
    at HTMLButtonElement.<anonymous> (angular.js:25023)
    at HTMLButtonElement.x.event.dispatch (jquery-1.10.2.min.js:22)

I have tried different syntaxes (then/fail then/catch success/error callback) but can't get around this error. Any ideas?

2) While saving data works, updating doesn't. I am getting the following error:

PATCH http://odata/test/JaydataTest//Items(21) 400 (Bad Request) @  odatajs-4.0.0.js:4366

Exception {name: "HTTP request failed", message: "The request is invalid.", data: Object} @ jaydata.js:4315

oDataProvider.js:4156 Uncaught (in promise) Exception {name: "HTTP request failed", message: "The request is invalid.", data: Object}

How to solve this error?

ODataController:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.ModelBinding;
using System.Web.OData;
using System.Web.OData.Query;
using System.Web.OData.Routing;
using Model;

namespace JaydataTest.Controllers.odata
{
    /*
    The WebApiConfig class may require additional changes to add a route for this controller. Merge these statements into the Register method of the WebApiConfig class as applicable. Note that OData URLs are case sensitive.

    using System.Web.OData.Builder;
    using System.Web.OData.Extensions;
    using Model;
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<Item>("Items");
    config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
    */
    public class ItemsController : ODataController
    {
        private ModelContext db = new ModelContext();

        // GET: odata/Items
        [EnableQuery]
        public IQueryable<Item> GetItems()
        {
            return db.Items;
        }

        // GET: odata/Items(5)
        [EnableQuery]
        public SingleResult<Item> GetItem([FromODataUri] int key)
        {
            return SingleResult.Create(db.Items.Where(item => item.ItemId == key));
        }

        // PUT: odata/Items(5)
        public IHttpActionResult Put([FromODataUri] int key, Delta<Item> patch)
        {
            Validate(patch.GetEntity());

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Item item = db.Items.Find(key);
            if (item == null)
            {
                return NotFound();
            }

            patch.Put(item);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ItemExists(key))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return Updated(item);
        }

        // POST: odata/Items
        public IHttpActionResult Post(Item item)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            db.Items.Add(item);
            db.SaveChanges();

            return Created(item);
        }

        // PATCH: odata/Items(5)
        [AcceptVerbs("PATCH", "MERGE")]
        public IHttpActionResult Patch([FromODataUri] int key, Delta<Item> patch)
        {
            Validate(patch.GetEntity());

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Item item = db.Items.Find(key);
            if (item == null)
            {
                return NotFound();
            }

            patch.Patch(item);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ItemExists(key))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return Updated(item);
        }

        // DELETE: odata/Items(5)
        public IHttpActionResult Delete([FromODataUri] int key)
        {
            Item item = db.Items.Find(key);
            if (item == null)
            {
                return NotFound();
            }

            db.Items.Remove(item);
            db.SaveChanges();

            return StatusCode(HttpStatusCode.NoContent);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool ItemExists(int key)
        {
            return db.Items.Count(e => e.ItemId == key) > 0;
        }
    }
}

jaydatamodules/angular.js (excerpt)

var originalSave = $data.Entity.prototype.save;
var originalRemove = $data.Entity.prototype.remove;
var originalSaveChanges = $data.EntityContext.prototype.saveChanges;

        $data.EntityContext.prototype.saveChanges = function () {
            var _this = this;
            var d = $q.defer();
            originalSaveChanges.call(_this).then(function (n) {
                cache = {};
                d.resolve(n);
                if (!$rootScope.$$phase) $rootScope.$apply();
            }).fail(function (err) {
                d.reject(err);
                if (!$rootScope.$$phase) $rootScope.$apply();
            });
            return d.promise;
        }
        return $data;
    }]);

Help is very much appreciated. Thanks in advance

I recommend you to check out the the JayData angular2 quickstart and jaydata odata v4 example repositories. Both use JayData 1.5.5 RC that doesn't need odatajs anymore as it already includes a patched version of it.

You have to include following module:

<script src="Scripts/jaydatamodules/deferred.js"></script>

http://jaydata.org/blog/how-to-work-with-the-jaydata-promise-interfaces

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM