5

I have an javascript object that includes some image strings as its property. Upon instantiating this object, an AJAX call is made immediately to populate this property.

My view functions, at the same time, tries to read newly instantiated instances and tries to display this object. As expected, the AJAX call may not have finished by then yet, so it will not be able to read the right image url.

One solution to this problem is to pass in some call back function with the AJAX call that modifies the source of image upon completion, but this is introducing a lot of dependency on the model and the view and I'm trying to keep my MVC as separate as possible, so my view function right now just takes that object as an parameter, reads all the properties, and shows it.

Making the AJAX synchronous isn't an option because I have quite a lot of these objects being initialized and only one will be displayed at a time, so making all AJAX calls synchronous will be too expensive of a tradeoff.

What's a good way to solve this problem? The view function is something in the form of:

function displayObj(object) {
    var prop1 = object.getProp1();
    // this could be the image file that depends on AJAX result
    var prop2 = object.getProp2(); 
}

Ideally, I would like to delegate this task to the getter, so that the view function doesn't have to worry about the interval state of the the object. The getter could handle this by checking whether the image is there yet, if not, wait, then only return if the actual image string is there. However, a blocking wait would for sure block the AJAX process so it's a deadlock, and non-blocking wait will let the getter return and the view function will get null data.

Please shed some light on this situation or suggest alternative ways that I can organize my code. Thank you very much!

jet
  • 698
  • 6
  • 12
  • `I have an javascript object that includes some image strings as its parameter`. This is wrong technically, because objects can't get **parameters**. Objects have **attributes**, which are also called **properties**. – Saeed Neamati Nov 22 '11 at 05:41
  • Yes, that's what I meant, properties, not parameters. – jet Nov 22 '11 at 05:44
  • The answer to this question depends a lot on which AJAX framework you are using (or if you are just calling XHR directly). For example, if you use one that has promises then adding the display update to the then() handler would be the answer. Can you shed some more light on what you are using? – chuckj Nov 22 '11 at 07:46
  • @chuckj I'm using jQuery, which does provide a nice callback mechanism, but as I mentioned, I'm hoping for a way to do this that doesn't introduce dependency on model and view. I'm trying to make controller the only middle man here. – jet Nov 22 '11 at 19:11

2 Answers2

0

I'd be a little bit less strict with the MVC roles and let the model object return the DOM <img> object.

// model object starts loading upon instantiation
var loader = new Loader();

// however the img tag is available immediately.
// the loader will update the src when ajax
// calls complete.
document.body.appendChild(loader.getImg());
Martin Algesten
  • 13,052
  • 4
  • 54
  • 77
  • Thanks, Martin. I feel that the my equivalent of your loader object here is actually model only, ie image url strings. It does not care about DOM at all. The view function is producing the img object on the fly and that's exactly when the source is being read, but may not be available. – jet Nov 22 '11 at 19:14
  • Yes, that's why I proposed my "less strict MVC". I find that many times in javascript you get cleaner code if you sacrifice a little bit of strictness. – Martin Algesten Nov 22 '11 at 20:33
  • Thanks for the advice. I'm not just trying to be strict for the sake of being strict. I just feel that having _mutual_ dependencies is a really bad idea. But as I mentioned, I eventually decided to just go with a complete synchronous model. Thanks anyways. – jet Nov 23 '11 at 08:32
0

Since, from your comments, you are using jQuery I recommend you call the done() method of the request returned from the ajax() method. For example,

var request = $.ajax("example.php");
request.done(notifyWhenSuccess);
request.fail(notifyWhenFailed);

This request returned by jQuery is a superset of the Promise pattern from CommonJS. Also, just because it is in jQuery don't cosider the ajax call part of the view but rather view it as part of the model. Use the done() method to update the model then notify the view with a data changed event.

chuckj
  • 27,773
  • 7
  • 53
  • 49
  • Thanks, @chuckj. This is indeed what I started implementing but it became messy after just a bit. The ajax call is already part of the model only, so the `notifyWhenSuccess` would be a view function, eg `view.updateImg`. but I have no guarantee that the view functions have been initialized and DOM objects created (since the DOM objects are created on the fly, drawing dependency on the model). In the end, other parts of the application basically forced me to a synchronous model so that's what I have now. – jet Nov 23 '11 at 08:28
  • I would sacrifice MVC purity to get my ajax calls to be async. A synchronous ajax call will kill reponsiveness and might lead your users to think the page is hung. – chuckj Nov 24 '11 at 09:29