Build Single Page Apps – Part 8 – JavaScript Data Services | John Papa

John Papa

Evangelist on the loose

Build Single Page Apps – Part 8 – JavaScript Data Services

...

I love to write code, but that doesn’t mean I want to write the same code over and over again. And I certainly don’t want to have to hunt down all that redundant code when I want to refactor a few pieces of it. That’s why I am a huge advocate for the Single Responsibility Principle (SRP) … or in simplest terms, I prefer to make smaller sets of code that have a primary focus. In JavaScript, that means modules like the ones below.

image

You’ll see examples of modules such as Models, a Data Service and a Data Context in my upcoming Pluralsight course titled “Building Single Page Apps (SPA) with HTML5, ASP.NET Web API, Knockout and jQuery”. (due to go live on Pluralsight in a week!).

You can catch up on the previous posts in this series here:

More on the Code Camper SPA

Part 1 – The Story Begins (What is the Code Camper SPA?)

Part 2 – Client Technologies

Part 3 – Server Technologies (the Data Layer)

Part 4 – Serving JSON with ASP.NET Web API

Part 5 – HTML 5 and ASP.NET Web Optimization

Part 6 – JavaScript Modules

Part 7 – MVVM and KnockoutJS

Part 8 – Data Services on the Client

Part 9 – Navigation, Transitions, Storage and Messaging

Part 10 – Saving, Change Tracking, and Commanding

Part 11 – Responsive Design and Mobility

Data Context

In the previous post (part 7) I discussed how I prefer the data binding techniques of KnockoutJS and the MVVM pattern in JavaScript. You can go check out an example of a ViewModel in that post. The ViewModel has a method named getSpeaker which defers its data retrieval to a datacontext module. It goes something like this:

datacontext.persons.getFullPersonById( currentSpeakerId() );

 

All view models in the application need data. When they need to get it or save it, they turn to the datacontext module who is responsible for getting or saving the data. Sound simple? Well, that’s the point. This data context module is like a client side repository.

The view model doesn’t care how the data is retrieved, it doesn’t care if its going to require an asynchronous call or not, it just wants the data. The datacontext hides all of the logic to retrieve (or save) the data so the view models just interact with the datacontext’s API.

Smart Caching

The datacontext in my app is smart enough to hang onto data once it gets it. When a request comes in for data, the datacontext checks if it has the data already. If so, it returns it. If not, it goes and gets it via an Ajax call (actually it defers the retrieval to a Data Service module … but more on that in a minute).

The datacontext’s getData method looks something like this (I shortened it just to get the main points across)

getData = function(...) {
return $.Deferred(function(def) {
// If the internal items object doesnt exist, 
// or we force a refresh
if (forceRefresh || !items) {
getFunction({
success: function(dtoList) {
mapToContext(...);
def.resolve(results);
},
error: function (response) {
logger.error(config.toasts.errorGettingData);
def.reject();
}
}, param);
} else {
itemsToArray(...);
def.resolve(results);
}
}).promise();
}

Consistent Expectations

Pay particular attention to the $.Deferred in this code. This function always returns a promise to the caller (the view model in my example). This provides a consistent expectations to the caller whether the data was retrieved from cache (which doesn’t require an async call) or an async Ajax call to the Web API on the server. This makes it easy to call the code and test it. (Yup, there’s unit tests in my app.)

Data Service

I mentioned that the data context handles getting and saving the data. That’s true, but more specifically it handles the job of figuring out how whether it has the data or not, and then if it does not have the data it asks the dataservice module to go get it.

The Data Service module (aka dataservice) makes the request for the data from whatever web service it needs to talk to. It has a simple interface so the datacontext can simply make a request like this:

dataservice.person.getPersons()

Remember that getFunction call up in the datacontext code we just looked at? If not, go look. I’ll wait.

That getFunction call is a delegate for the dataservice.person.getPersons (for example). So if we call it directly we could do it like this:

dataservice.person.getSpeakers({
success: function() { ... },
error: function() { ... }
});

The Payoff

This abstraction of data services and data contexts makes it simple to make calls for the same data from multiple places (including view models). So I reap the benefits of:

  1. Code re-use and less repeating myself (DRY)
  2. Testable modules
  3. Easier maintenance (when refactoring)

In the course I go deeper into these topics and how the data service promotes the use of switching between sample (or mock) data and live data. There are also modules for model factories for the observables (if you so choose to create them).

Make it Your Own

I’m very excited to see how people refactor the sample app I include in the course (for Plus subscribers) to add their own ideas. There are so many other angles I would love to have hit, but I made the decision early on to choose one path and explain it.Otherwise there was too much risk of getting myself derailed. The course follows one option for building a SPA but I also can see myself expanding on it for a follow up later. Sigh … but first, I’ll finish this series (next up, navigation) … then I need a vacation Smile

 

UPDATE:

I wrote myself a reminder (and promptly forgot) to mention 2 libraries that could replace my datacontext module. I am looking forward to when they go to their final release stage: Upshot.js and BreezeJS. Upshot (by the Microsoft ASP.NET team) has been around for a while in pre-release form, but it’s not at a point where I feel comfortable using it just yet. However it has a lot of potential and I am all over it once it is released. The other is BreezeJS, by ideablade. These guys have been in this space before with WinForms, Silverlight, WPF and are BreezeJS is there new JavaScript offerring. Breeze is not out yet but will be here soon, I am told. Neither is something I would use today, but both are intriguing enough where it could dramatically simplify (and reduce or eliminate) my datacontext module with the same and even more functionality. I’m all for “better”!

tags: data patterns pluralsight SPA
  • Shawn Hubbard

    My concern here is that it seems like a lot of complexity is being built into this, where on the server-side I could write similar testable code in a simpler fashion. I’m guessing this isn’t a JS limitation. Is it your style preference, or some other benefit I’m not seeing?
    Loved the series so far and really looking forward to the Pluralsight course! I’m a server-side guy that is trying and can’t quite make the context switch into JS, and hopefully this helps screw in the lightbulb.

  • john

    Hi Shawn,
    You can certainly write everything n the server using PHP, ASP.NET, ASP.NET MVC, or another server tech. This app demonstrates one user story for a SPA (see part 1), where you have low connectivity and need quick access to the data. It really is very similar to writing a Silverlight or Flash based application, where the presentation logic is all client side.
    Another key point is that the business logic is still server side. The presentation logic is what is client side. I would not be a fan of business logic in the client, unless absolutely needed.
    There is complexity in it, but like most code, what seems complex at first becomes clear once you start using it.
    There are parts of this app that I love and parts I really want to make smoother. The biggest piece for me is the data context … if Upshot was stable I would have considered that, but it’s not out yet. There is a new library coming soon called breezejs, but again, it’s not ready just yet so I rolled my own.
    Keep the questions coming, I am sure a lot of people are in the same boat.

  • ward bell

    Hi Shawn – You’re right … the datacontext is definitely a consequence of this “SPA” style of application and not intrinsic to JavaScript.
    On the server, you receive a request, get the appropriate data, muck with it, send back a result and then forget about it. You don’t preserve state between requests.
    In a stateful client, the data hang around longer … a lot longer. In Code Camper they hang around for the entire user session.
    That’s not a “good” thing or a “bad” thing. It’s the “intended thing”. It suites the Code Camper scenarios in which a conference attendee needs immediate access to session information in a low bandwidth environment.
    It also fits for another central characteristic of “SPA” apps: many views pivoting around the same data. Code Camper has something like 6 views that look at Session data from different angles. Each view has an independent perspective on Sessions. To keep the experience crisp, you the views to share the same Sessions; you don’t want them each to have to go back to the server every time.
    Code Camper facilitates sharing by holding Sessions in the DataContext and making the DC available to any ViewModel that needs Sessions.
    Bringing this off takes a bit more work than in a traditional web page app … which forgets the data as soon as it responds to a single request.
    I’m not arguing that a SPA is better than a web page app. I’m just trying to clarify the difference in architectural styles … and show that the complexity is in the nature of the problem-to-be-solve, not in the technology per se.
    Cheers, Ward

  • GA

    I can’t stop drooling… I can’t wait for this course to come out!
    John, even if upshot or breeze were out and fully functional, wouldn’t you still keep your datacontext as or close to as is? It’s hard to say without having all the code/course available, but it seems like upshot/breeze would live somewhere behind the datacontext or possibly somewhere behind the dataservice? you mentioned above that the dataservice promotes toggling between mock data and live data. my guess is that when “live” upshot would be used. With the little info I have to guess work with, my guess is that datacontext would be injected some “dataservice” implementation, one that goes against upshot/breeze and one that goes against the mock. not sure but I’m waiting to see how this all works out!
    Thanks again

  • john

    GA – It’s tough for me to exact on how they would integrate until I see their final versions. But yeah, I’m thinking that they would be used and hook into the dataservice (though they could do that job too if you want)

  • http://www.nunooliveira.pt Nuno

    Hi John! This seems to be a great course, and I can’t wait for it to come out! My question is if the project code be available not just for Pluralsight Plus subscribers as I’m a month subscriber! For example in Dan Wahlin’s “Building ASP.NET MVC Apps with EF Code First, HTML5, and jQuery” course, he made available the code for the AccountAtAGlance app.
    Thanks,
    Nuno

    • Steve Hueners

      Can’t help but throw in this unsolicited, unaffiliated recommendation: the code from CC is easily worth a month’s subscription to PS to say nothing of one month’s extra cost to bump from bottom tier to full boat.

  • john

    Hi Nuno,
    Thanks for the comments. Pluralsight makes the demo code available to all “Plus” subscribers.

  • N

    Hi John,
    Awesome course!
    I have a quesiton about the “add” function from the EntitySet.
    What happens in this function exactly? What if i want to add a new entity:
    datacontext.sessions.add(new Session());
    the new session has not an id on the client side. Will the Server return the new id after the PUT/POST call?
    If it so, what if i update the new session (which has no id) directly? How the Server knows, which entity he needs to update?
    var newSession = new Session();
    datacontext.sessions.add(newSession);
    newSession.myProperty = “New Value”;
    datacontext.sessions.updateData(newSession);

  • john

    Hi N,
    Thanks for the feedback and questions. In the app, the “Add” method sends an entity to the server (through the web api) and ultimately inserts it into the database. The web api method returns the newly created entity back, with its new ID. The datacontext receives it and stores it on the client in memory.
    If you then update the entity on the client, you have the ID so you are all set. In the CC app, once the new entity has been added back to the datacontext (which happens after the call to web api is done) you can grab that item from the datacontext and update it.
    BTW – you can follow this logic by favoriting a session. That will add a new attendance record. You can follow the steps using your favorite browser debugging tools if that helps. I cover some of this in the “Saving” module too.
    Hope this helps!

    • Shawn

      John,

      First let me say that I am enjoying your course immensely. I am working through your source code trying to implement your architecture with a test project and have a question I was hoping you could answer. Let’s say I wanted to create a screen to add a new speaker. Would you reuse vm.speaker with some kind of “Add or Update” flag or would you create a separate viewmodel for handling the add operation?

  • Stacy

    This is good stuff. Thanks!
    “the “Add” method sends an entity to the server (through the web api) and ultimately inserts it into the database. The web api method returns the newly created entity back, with its new ID. The datacontext receives it and stores it on the client in memory.”
    When moving to a different view after an ADD, this will produce unnecessary delay. Can you just create an Id on the client, then show the next view, THEN send the data to the server? Server just returns bool success/failed insert?

  • john

    Stacy,
    Sure, you could do that as long as you handle the return value. If it errors out, you might want to send the user back to the “add” view so they can correct their mistake. This would be a lesser experience for the user if it does fail tho.
    If you want to allow adding multiple items you could queue them up on the client and then send back to the server in a batch too. It all depends on your goals and how well you handle the scenarios.
    But yeah, that option works too.

  • Graham

    Hi John,
    The last 2 links (http://johnpapa.net/spapost9 and http://johnpapa.net/spapost10) appear to be broken.
    I have a question also. I am writing an SPA using similar techniques to capture data on a mobile device, where connectivity may be flaky. Is there an equivalent success / error I can use on the submit so that I can inform the user that the data they have entered has not yet been saved back to the database?
    The way I have it at the moment, is that I have bufferchanges false, and I simply do this for a new item:
    self.SaveNew = function () {
    self.engagements.push(self.newObject);
    }
    upshot then handles calling submit on my controller for me, but at the moment I have no way of informing the user whether the save worked.
    Thanks

  • john

    Graham,
    Thanks for the feedback.
    Hmmm. The links work for me. They are http://jpapa.me/spapost9 (using bit.ly with jpapa.me).
    I’m not sure I follow your question. Why don’t you know when there is success or failure? Ajax calls generally have both callbacks.

  • Matt Kruczek

    John,
    Any chance that when upshot.js comes out with the final version you could do a blog about replacing the existing code with upshot?

  • john

    Matt,
    If that happens I would consider taking Upshot, Breeze, and any other good option and showing how it could be integrated. But first, I have to wrap up my Windows 8 course :)

  • Martin

    Hey John :)

    I have a question concerning ErrorHandling.
    To take an example from CodeCamper.

    In AttendenceController there is a Deletefunction, here we simply
    return new HttpResponseMessage(HttpStatusCode.NoContent);

    If we in this part return
    return new HttpResponseMessage(HttpStatusCode.Conflict);

    Then we hit “error: function (response)” in DataContext.js deletefunction. But response is “null”.

    But Ive tried a couple of different ways to return something to the client, but the response is still “null”.

    Its propably trivial what Im doing wrong but I would appretiate some help.

  • khuzema

    Where we can have a source code for this. Thanks

    • John

      Pluralsight has a “Plus” subscription where you can get the source code and other materials.

      • Khuzema

        Yes. I know about that. I thought its available other than that (I am subscriber not Plus subscriber though). No issues. I have lengthy feedback. I will post it later.

  • oliver

    John, hats off for this great course. It has opened my eyes on some very cool techniques and concepts.

    I’m working on a SPA which is basically a bug / todo management system. Since you’re getting all the data in the bootstraping phase, how do you handle stale data ? I mean what if someone else modifies an entry and you don’t it the refresh button, you’ll be looking at stale data.

    Thanks

    • John

      Oliver,

      Thanks for the feedback. This is where I would introduce two features to help with change management of stale data: expiration of data and SignalR. Expirations are self explanatory where they refresh when data expires (or attempt to in case network is not available). SignalR is great for notifying when changes happen on the server.

      If dat is in constant flux, I would caution against caching it on the client for too long anyway. But in my scenario, it was pretty solid.

      Hope this helps!

  • adam berendt

    John,
    I have gone through your pluralsight training course on SPA apps. When I try to open the code camper solution in visual studio 2012 ultimate it loads like halfway and hangs up. I then can never get it to come up. It seems to work for a day or two and then lock up when I try to open the solution. Have you heard any other complaints about it? I get the dreaded visual studio is busy window and it just is locked up.

    • John

      Adam,

      Sorry about that. I haven’t seen this personally. You may try removing items form the sln file first to see where your issue is. Also, make sure you have the latest code, as we did update a few files a few days after I released the course.

  • Han

    John:

    Awesome course. It really opened my eyes to the potential of JavaScript/Html/CSS. I can’t imagine how much work you put into this. Being a javascript newbie, I have to admit the javascript code in CodeCamper spa was pretty overwhelming the first time I looked at them. But I toughed it out, and was able to immediately apply SPA style to one of the projects I’m working on with all the client-side best practices (“Ravioli code”).

    I do have a question for you. In your various view model js files (for eg, “vm.favorites.js”) you have the “activate()” method. But I don’t see where, when or how it’s being called. I know it is b/c that’s how you get the data from the “datacontext”. But I just don’t see where. For me to get my app to work, I had to call the “activate()” method in my vm. Could you explain this to me?

    Thanks a lot.
    Han

    PS: Just a thought, maybe a more simplified tutorial on SPA with just the core concepts will help someone like me to not become overwhelmed at first. I do appreciate all the best practices (which is a ton!) you put into this tutorial, but it does take a lot of perseverance and determination to go thru your code and understand them.

    • John

      Han,

      Thanks, I’m glad you liked the Ravioli :)

      The activate method is called by the router module when someone navigates to a new View. Look for the vm.callback in the router. It starts when the viewmodel is registered with the router. At that time the router is told which viewmodel to invoke for a route, and which method in the viewmodel to call (later when a View is navigated to). I talked about this in the Nav module, if memory serves me.

      I am starting to compile ideas for a SPA Fundamentals course. I have some content in mind that I want to get to, and I am listening to feedback from this course too. The Fundamentals course would be a more simplified version covering just the basics of the client. I also want to do a follow up to the SPA to add in other content like SignalR :) So basically, I have a lot to think about. LOL

      But first, I am working on a TypeScript course with Dan Wahlin

      • Han

        John:

        Ok, I see. Thanks for the quick reply.

        I like the idea for a SPA fundamentals course, and I’m also hoping, along with SignalR, UpshotJS/BreezeJS will be ready for prime time as well by then. (Although I benefited a lot from understanding and writing my own ‘datacontext’ layer.)

        I look forward to your course on TypeScript as well. Have you or do you know others who have used TypeScript extensively since it came out? It looks really enticing for a C# developer. I”m just wondering how well it works in practice.

        Thanks,
        Han

  • Laran Evans

    I have some questions about building SPAs.

    1) How do you give users a link for a specific screen, for instance to bookmark?
    2) How does the browser back-button work in an SPA?
    3) How do you test an SPA with a tool intended to simulate user interaction, such as Selenium?
    4) How do you track user behaviors using a tool like New Relic (specifically, if all requests go to the same page, it’s impossible to tell which screens are loading quickly and those that are loading more slowly).
    5) How do you do something like A/B testing in an SPA?
    6) Isn’t it a lot more work to build out a full MVC stack on the front end when you’ve already got a full MVC stack on the backend?

    Thanks for taking the time to write all this up. I really look forward to learning more.

    Thanks!

  • Christian

    Hi John,
    I’m an former MS FTE and your best fan :)
    I was wondering if you could share your current breezified SPA code to your pluralsight subscribers? I’m having a hard time with the rather complex datacontext since I’m using SPA as a base for a new project. Thank you for your great course.
    Christian

    • John

      Hi Christian,

      Thanks, glad you like the course :)

      Short answer is yes, if there is interest I’ll explore some options. Longer answer is that Breeze is currently in beta abut I am working on “breezifying” the Code Camper SPA. As I go through this I am reporting back feedback to their team (almost all of it positive so far). Once breeze goes RC and has its API established and a few things finalized, I’ll start working on a CodeCamper version. At that point if there is interest I’ll consider updating the course.

  • Gabor Dolla

    Please try jaydata (jaydata.org), it gives you client side oData, full CRUD to Entity Framework in a few lines and also support Knockout.js.

  • Javier

    Hi John!
    Excelent post with lots of guidelines, very well argued and experience, experience, experience.
    Thanks sir.

    Is there any chance to have access to the complete code? Mostly interested in client-side code, since I am working with a JEE-based backend but probably will re-write to Spring (course, and already working with KnockoutJS for my client side).

    javier

  • Brooks

    Hello John. I’ve studied your Code Camper SPA and the associated Pluralsight course, which helped me a lot in creating my own SPA. However, I’m seeing a weird issue and hope you can help me out. My deadline for completing the app is almost here, and I’m stuck.

    Anyway, my app is very similar to Code Camper in the sense that I have a list of “things” and then the details of an individual “thing.” Whereas you have sessions and session, I have alarms and alarm. I’ve used the Code Camper code, changing sessions to alarms and session to alarm (and, of course, changing the fields of the model/database).

    In vm.alarm (your vm.session), I have (sorry in advance for the console lines, I’m trying to debug, but it’s exactly like your code):


    getAlarm = function (completeCallback, forceRefresh) {
    var callback = function() {
    if (completeCallback) { completeCallback(); }
    validationErrors = ko.validation.group(alarm());
    };
    console.log(“inside getAlarm call getAlarmById”);
    console.log(“inside getAlarm selectedAlarmID: ” + selectedAlarmID());
    datacontext.alarms.getAlarmById(selectedAlarmID(), {
    success: function(s) {
    console.log(“in getAlarm, success, s.alarmID: ” + s.alarmID());
    console.log(“in getAlarm, success, s.reasonReasonActionID: ” + s.reasonReasonActionID()); // I HAVE A VALUE HERE e.g., 55
    console.log(“in getAlarm, success, s.actionReasonActionID: ” + s.actionReasonActionID()); // I HAVE A VALUE HERE e.g., 10
    console.log(“in getAlarm, success, s: ” + ko.toJSON(s));
    /*
    Printed out to see what’s in s -> s: {“alarmID”:4614,…,”reasonReasonActionID”:55,”actionReasonActionID”:10,…,”isDirty”:false}
    */
    alarm(s);
    console.log(“in getAlarm, success, alarm: ” + ko.toJSON(alarm));
    /*
    Printed out to see what’s in alarm -> alarm: {“alarmID”:4614,…,”isDirty”:false}
    NO reasonReasonActionID OR actionReasonActionID!!!
    */
    console.log(“in getAlarm, success, alarm.alarmID: ” + alarm().alarmID());
    console.log(“in getAlarm, success, alarm.reasonReasonActionID: ” + alarm().reasonReasonActionID()); // I DO NOT HAVE A VALUE HERE!!! IT’S undefined
    console.log(“in getAlarm, success, alarm.actionReasonActionID: ” + alarm().actionReasonActionID()); // I DO NOT HAVE A VALUE HERE!!! IT’S undefined
    callback();
    },
    error: callback
    },
    forceRefresh
    );
    },

    Basically, when I call getAlarmById in datacontext, the alarm object is correctly/successfully returned into s. But, when I put s into the alarm ko.observable, the two fields — reasonReasonActionID OR actionReasonActionID — are just gone.

    Do you have any idea what could be going on and how to “fix” this issue?

    I’ve been struggling with this for a while now. And, the fields reasonReasonActionID and actionReasonActionID are in my model.alarm and are returned from my Web API call.

    Help? Thanks!!!

  • http://blog.majcica.com Mario Majčica

    Hi John,

    I was following your videos on Pluralsight. Did you really had a need to include the underscorejs lib? I saw that you use just a couple of functions like reduce and each. All of that things are achievable with the pure JS, like with Array.reduce and Array.forEach. By changing the interested line of code, would it be possible to get rid of underscore library or it is used also in other context which I missed to see?
    By the way, very nice videos, I like your approach even if often over complex. It brought my knowledge about the JS on the higher level.

    Thanks

    • John

      Mario – Those features (forEach, map, etc) rely on ES5, so if your browser supports ES5 then you can use them and not underscore.

  • http://blog.majcica.com Mario Majčica

    Great, as the requirement for my current projects are IE9+ I should go fine without _. A little bit less libraries to carry by.

    Thanks

  • http://www.DansGreenShoes.com Dan Hickman

    John,
    Thanks again for the great source code, blog and video. I am having analysis paralysis and hoping you can help me. Struggling with how to wire up navigational properties.

    I have a datacontext that looks like this:
    var datacontext = {
    applications: applications,
    proficiencys: proficiencys,
    };
    So, I have a model.application and model.proficiency. Each Application contains 1 to many Proficiency(s).

    My model.application needs access to its list of Proficiency(s). I see 2 different options:
    1) model.application.proficiencies = ko.observableArray() or
    2) model.application.proficiencies = ko.computed(function () {})

    In CodeCamper, it shows model.person.speakerSessions as a ko.computed. Should I do the same and if so, why?

    My 2nd question is related to the datacontext to support the navigational property. I believe I need to extend datacontext.proficiencys with a function like “getLocalProficiencysByApplicationId”, agree? If yes, how would I do implement this? (Code Camper has the “datacontext.speaker-sessions.js” file, but I feel like there might be an easier way.)

    Thanks again!
    Dan

  • David

    Hi John,
    Thanks for great course.
    In the datacontext.mapToContext function you “return items;” and add a comment “// must return these”.
    Why is this? The items property is passed in as a parameter and updated during the function?
    I removed the return statement and removed the assignment from the call (in getData) and the application works fine so far.

    • John

      David – At one point while building the app up it needed to be returned. That point may have been long ago, however :) . As long as there is a valid observableArray, its fine. Sorry for the confusion.

  • Simon

    John, i have gone through the course and developing an application based on CodeCamper. I’m gettting data upto itemsToArray function. However when itemsToArray function is called, results is not populating. I haven’t changed itemsToArray function.

    Any suggestions?
    thanks
    Simon

    • John

      Simon – When you get your data back, I assume its from an async operation. In that case the original calling function needs to know when that operation is done, so you either need to use a callback or resolve a promise. That’s just one guess at what may be causing this, assuming your bindings are right, etc.

  • http://www.wordpress-fr.net/support/profile.php?id=52740 http://www.wordpress-fr.net/support/profile.php?id=52740

    Hmm is anyone else experiencing problems with the
    images on this blog loading? I’m trying to find out if its a problem on my end or if it’s
    the blog. Any feedback would be greatly appreciated.

  • http://www.mckinsey.com Brian Reynolds

    Great app. Been using your pluralsight course and advocating it to others too.

    The capitalization of EntityFramework object IDs ends up being a bit tricky when trying to make modifications to code camper to experiment with it. We took your code camper and started making some modifications to it for an internal demo. If the backend EntityFramework classes use an ID of “ID”, the model.mapper gets confused because it wants them to be “id” but they turn out to be “iD”. Also, we dumped in the OData additions for the WebAPI (used Web API OData RC1 because RC3 filters are fubar) to show how to do other types of queries and it further messed with the ID variables because it forced them down to lower case so even if the EntityFramework class had ID’s of “ID”, they end up being “id” on the client side. If you make a small change to your model.mapper, you can handle a number of scenarios:

    getDtoId: function (dto) {
    var id = dto.id || dto.iD || dto.ID || dto.Id;
    return id;
    },
    fromDto: function (dto, item) {
    var id = dto.id || dto.iD || dto.ID || dto.Id;
    item = item || new model.MyEntity().id(id);
    item.myAttribute1(dto.myAttribute1)
    .myAttribute2(dto.myAttribute2)
    .myAttribute3(dto.myAttribute3)
    item.dirtyFlag().reset();
    return item;
    }

%d bloggers like this: