1

I am having an issue with backbone.js and the model.save() method. I have included a complete example below although without the three libraries needed.

I have a tag model, a tag collection model, and a model to represent some selected items in my UI, called search criteria.

I am getting a url error when attempting to save the model after I have manipulated the search criteria's collection of tags. This example illustrates the issue.

It appears that on the final call to save in this example, backbone cannot resolve the url which is defined in the tag collection model.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test</title>
    <script src="Scripts/Libraries/jquery-1.6.1.js" type="text/javascript"></script>
    <script src="Scripts/Libraries/underscore.js" type="text/javascript"></script>
    <script src="Scripts/Libraries/backbone.js" type="text/javascript"></script>

    <script language="javascript" type="text/javascript">

        $(function () {

            // Simple model for a tag. Tags have an id and a title.
            var TagModel = Backbone.Model.extend({});

            // Collection for tags.
            var TagCollection = Backbone.Collection.extend({
                model: TagModel,
                url: "tags"
            });

            // Sample model to hold a set of "selected" search criteria.
            // Includes search text and a collection of "selected" tags.
            var SearchCriteriaModel = Backbone.Model.extend({
                defaults: {
                    "searchText": "",
                    "tags": new TagCollection()
                }
            });

            // Create master tags collection.
            window.tags = new TagCollection();
            window.tags.refresh([
                { id: 1, title: "Tag A" },
                { id: 2, title: "Tag B" },
                { id: 3, title: "Tag C" }
            ]);

            // Create search criteria.
            window.searchCriteria = new SearchCriteriaModel();

            // Should be 3 tags.
            console.log("Should be 3 tags in master tags list.");
            console.log("Count = " + window.tags.size());

            // Should be 0 tags in criteria collection.
            console.log("Should be 0 selected tags.");
            console.log("Count = " + window.searchCriteria.get("tags").size());

            // Update tag title for tag 1.
            var tag = window.tags.get(1);
            tag.set({ "title": "Tag AA" });

            // Save tag.
            console.log("Try to save tag. Should attempt PUT to /tags/1. WORKS.")
            tag.save();

            // Add tag to search criteria.
            window.searchCriteria.get("tags").add(tag);

            // Should be 1 tag in criteria collection now.
            // I am not moving the tag, but rather wanting to simply add a reference to the tag to the
            // criteria collection.
            console.log("Should be 1 selected tags.");
            console.log("Count = " + window.searchCriteria.get("tags").size());

            // Should STILL be 3 tags in the master list.
            console.log("Should be 3 tags in master tags list.");
            console.log("Count = " + window.tags.size());

            // Update tag title for tag 1 again.
            var tag = window.tags.get(1);
            tag.set({ "title": "Tag AAA" });

            // Save tag.
            console.log("Try to save tag. Should attempt PUT to /tags/1. WORKS.")
            tag.save();

            // Remove tag from criteria. Simulates someone "deselecting" a tag from the search.
            window.searchCriteria.get("tags").remove(tag);

            // Should be 0 tags selected.
            console.log("Should be 0 selected tags.");
            console.log("Count = " + window.searchCriteria.get("tags").size());

            // Save tag. FAILS.
            console.log("Try to save tag. Should attempt PUT to /tags/1, but does not. Instead throws error 'A url property or function must be specified'.");
            tag.save();

        });

    </script>

</head>
<body>
    <h1>Test</h1>
    <p>Backbone test page.</p>
</body>
</html>

Any thoughts? Thanks!

UPDATED

I updated the code to help illustrate that I am not moving the tag between collections, but rather adding a reference to the tag to a second collection. Then, when I remove the tag from the second collection (not the first), Backbone cannot resolve the first collection, and then cannot get the url for saving.

I am confused as to why removing the tag from one collection would have an impact on the reference to that tag in a separate collection.

I am coming from a C# background. Maybe objects and collections work differently here.

2 Answers 2

1

You've got two collections of tags running (one on window and one defined in your SearchCriteriaModel) and you appear to be moving a tag between the two collections

When you execute this line of code:

window.searchCriteria.get("tags").remove(tag);

The link between that tag and a collection is lost.. the URL is determined from the collection.

Note that if you remove the line above, your tag saves as it gets it URL from your window.tags collection.

Ps.. good question, well asked, nicely formatted code sample demonstrating the problem.

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

4 Comments

Thanks. I don't think I am "moving" the tag. The master tags collection is my main list of tags. The search criteria tags collection is used to store "selected" tags. I am wanting to have a reference to the tag in both collections. The main collection is used to display my list of tags, and the other collection is used to keep track of the selected tags so I can do other things with it, like send the criteria to a find function. I am not sure why the collection reference would be lost when the tag is removed from the criteria collection. The tag is still part of the main collection.
Check the annotated backbone.js source code at documentcloud.github.com/backbone/docs/backbone.html you will see that when you perform a collection.remove(model) that the link to the collection is cleared (model.collection) in collection._remove. I stand by my answer. A model has just ONE in-built navigable link to a collection. And that link is one of the two ways that the model can use to determine a URL.
I did not mean to question your answer, just understand it better. Sorry if it came across that way. I understand better now. I guess I need to figure out a different way to handle the "search criteria" collection of tags. Tags will be added and removed from this collection many times, but need to remain in the master collection (with the collection reference in tact.) If removing the tag from one collection destroys this reference, even though the model is still part of the other collection, I will have tom come up with something different. Thanks again!
Hi Kevin, I wasnt offended in any way. Your followup question is worthy of a good answer. I would post a seperate question for that. A simple object with the search text and an array of models would suffice to get you going I think.. It doesn't need to be a backbone collection.. Good luck!
0

Don't know if this solves your problem, but you should first change your url to "/tags" instead of just "tags"

1 Comment

Thanks, but that is not the issue. I am focusing on the problems that occur relating to Backbone being able to even resolve a url at all on the final example call to save.

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.