3

I am doing an AJAX call to a controller method on my ASP.Net MVC web site. That method is sending back some custom objects JSONized.

I'm having trouble treating lists from these C# objects as Javascript arrays and I'm just new enough to Javascript not to understand what the problem is.

I have an object called Animations. Each Animation has a List named Frames. If I try to pass the JSONized Frames e.g. currentAnimation.Frames to a Javascript method expecting an array of integers I don't get an exception but the receiving method doesn't get an array of integers like it expects so it also doesn't do anything with the data.

Here is my Javascript. Notice it passes "this.spriteSheet.Animations[sheet].Frames" to the "addAnim" method. This doesn't work.

for (var sheet in this.spriteSheet.Animations) {

    var animation = this.addAnim(this.spriteSheet.Animations[sheet].Name, this.spriteSheet.Animations[sheet].Speed, this.spriteSheet.Animations[sheet].Frames);

    if (this.flip) {
        animation.flip.x = true; ;
    }
}

And here is some Javascript I modified to work (although I don't know if it's the best solution and I still don't really know what the problem is):

for (var sheet in this.spriteSheet.Animations) {

        var frames = new Array();

        for (var frame in this.spriteSheet.Animations[sheet].Frames) {
            frames[frame] = this.spriteSheet.Animations[sheet].Frames[frame];
        }

    var animation = this.addAnim(this.spriteSheet.Animations[sheet].Name, this.spriteSheet.Animations[sheet].Speed, frames);

    if (this.flip) {
        animation.flip.x = true; ;
    }
}

Here is my controller action code:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetPlay(int id)
{
    // get the game that has been requested
    Cherub.Common.Logic.Game game = new Common.Logic.Game();

    // get the play data
    Play play = game.GetPlay(id);

    return Json(play, JsonRequestBehavior.AllowGet);
}

I am calling the controller action with JQuery's ajax call:

$.ajax({
        type: "GET",
        url: ajaxUrl,
        contentType: "application/json; charset=utf-8",
        data: {},
        dataType: "json",
        success: functionSuccess,
        error: functionFailure,
        cache: false
    });

Here's a small section of the JSON coming back from the controller action:

"Animations":[{"Name":"bob","Frames":[0,1,2],"Speed":0.2}]

Here's my SpriteSheet class

public class SpriteSheet
{
    public SpriteSheet(string name)
    {
        Animations = new List<Animation>();

        switch(name.ToLower())
        {
            case "sylph":
                Sheet = "media/Sylph.png";
                Animations.Add(new Animation { Name = "bob", Frames = new List<int> { 0, 1, 2 }, Speed = .2f });
                FrameSize = new Vector2D { X = 94, Y = 125 };
                break;
        }
    }

    public string Sheet { get; set; }
    public List<Animation> Animations { get; set; }
    public Vector2D FrameSize { get; set; }
}

public class Animation
{
    public string Name { get; set; }
    public List<int> Frames { get; set; }
    public float Speed { get; set; }
}
5
  • Can you use Firebug to examine the JSON result of your controller action? Also, what is the type of Frames in your C# object? Commented Jul 26, 2011 at 15:17
  • Frames is a List<int>. I used chrome's debugger to examine the variable. It said that it is an object. The length property doesn't exist like you would expect on an array, but you can index into it an get the values like Frames[0]. Commented Jul 26, 2011 at 15:23
  • You can index into any object in javascript, and it will give you the properties on that object. For example, {a: 1, b: 2, c: 3}, when you iterate over this object, you'll get a, b, and c. That's why I'm interested to see the actual JSON string being produced. Also, how are you producing this JSON? Can you show the MVC action's code? Commented Jul 26, 2011 at 15:34
  • Ok, yeah that makes sense. I updated the post with the Javascript code I'm using to call the controller method as well as the controller method itself. I'm not sure how to get the JSON, I was interested in looking at that as well. I don't have firebug installed as I've always had a better experience with chrome's debugger. Do you know how I can get that information for you in the chrome debugger? Commented Jul 26, 2011 at 15:42
  • Nevermind, I had a really easy way to access the JSON that I wasn't thinking of. A ton of JSON is coming back so I only copied the section with Animations. I hope that helps. Commented Jul 26, 2011 at 16:00

3 Answers 3

2

From the description, it sounds like Frames is being converted into something like this:

{0: 1, 1: 2, 2: 3}

... whereas you want something more like this:

[1, 2, 3]

Both of these javascript objects can be accessed like this: obj[0], but only the latter is an actual array. Doing a for loop over the former will yield [0, 1, 2], whereas doing a for loop over the latter will yield [1, 2, 3].

If I'm right, then you need to look at the code you're using to serialize Frames into a JSON string, and make it treat Frames as an array-like object.

Update

Well, I'm stumped. Everything looks like it ought to be working correctly to make Frames an Array in javascript.

Sign up to request clarification or add additional context in comments.

2 Comments

A for loop over both data structures will yield 0, 1, 2. Only the order of object properties is not guaranteed.
@Felix: True. Thanks for catching that.
1

Based on the sample in your question, Animations and Frames are arrays - but you're treating them like they are objects.

for..in loops are useful for iterating over the properties of an object, but you need to loop through each element in the array using a simple for loop instead.

If you change your for .. in loops, you should get the result you're looking for:

var anims = spriteSheet.SpriteSheet.Animations;

for(i = 0; i < anims.length; i++) {

    var frames = new Array();
    for(j = 0; j < anims[i].Frames.length; j++) {

        frames[i] = anims[i].Frames[j];

        ...

9 Comments

Animations doesn't have a length property (part of the problem) which is why I used the for ... in syntax.
If it's an array, it should have a length - are you sure that it's in the form: "Animations":[{...}, {...}]. Can you post a sample of the spriteSheet object so we can see some context?
I updated the original post to contain the SpriteSheet class and I'm sure that's the JSON coming back. I hit the controller action directly and copy and pasted it from that.
I've mocked up what I expect your JSON to look like based on your controller at jsfiddle.net/HmD5u, @omatase. Can you confirm if the data structure you're receiving from your service matches the structure I've derived?
Yes I can confirm my controller's output matches that structure. What's different is that all of my properties are put in quotes. Here is the same segment as it is being output by the controller: "SpriteSheet":{"Sheet":"media/Sylph.png","Animations":[{"Name":"bob","Frames":[0,1,2],"Speed":0.2}],"FrameSize":{"X":94,"Y":125}}
|
0

My advice is not to use for...in loops. I've had cross browser "weird" issues before that just don't seem to make sense and all the JS gurus suggest just using regular iterative for loops

If you're trying to cut down the JS into something a little more managable then I would thoroughly recommend using something like Coffee Script which is much more suited to writing algorithmic code like you will in your game.... the class functionality is particularly sweet too!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.