How do I null properties of Serenade object in a correct way?

24 views
Skip to first unread message

Kirill Grishin

unread,
Jul 17, 2012, 5:34:21 AM7/17/12
to seren...@googlegroups.com

Here is a situation:

I have 3 classes: a collection of Name instances which are nested into PaymentMethod which is a property of Invoice.

I create some instances of Name, put them into PaymentMethod, than assign PaymentMethod to Invoice.

Then I render a view with an Invoice instance. It renders without any problems. Then I set Invoice.PaymentMethod to null the view is re-rendered without any problems (and PaymentMethod disappears from the screen).

But when I assign PaymentMethod instance back to Invoice, an error is thrown:

 

TypeError: this.anchor.parentNode is null

return this.anchor.parentNode.removeChild(this.anchor);

 

It occurs in DynamicNode.prototype.remove()

 

Here is full code:


var Invoice = Serenade.Model.extend('Invoice');

Invoice.property('paymentMethod');

               

var PaymentMethod = Serenade.Model.extend('PaymentMethod');

PaymentMethod.property('type');

PaymentMethod.hasMany('names', {

    as: function() { return Name}

});


 var Name = Serenade.Model.extend('Name');

Name.property('value');

               

var myInvoice = new Invoice();

var myPaymentMethod = new PaymentMethod({type:'transfer'});

var name1 = new Name({value:'Citibank '});

var name2 = new Name({value:'New York Branch'});

 

myPaymentMethod.names.push(name1);

myPaymentMethod.names.push(name2);

 

myInvoice.paymentMethod = myPaymentMethod;

 

Serenade.view('myView', '\

div\n\

  p "Payment instructions: "\n\

    - in @paymentMethod\n\

        span @type\n\

');

 

Serenade.view('myViewCollection', '\

div\n\

  p "Payment instructions: "\n\

    - in @paymentMethod\n\

      - collection @names\n\

        span @value\n\

');

 

var view1 = Serenade.render('myView',myInvoice);

var view2 = Serenade.render('myViewCollection',myInvoice);

 

window.onload = function(){

                document.body.appendChild(view1);

                document.body.appendChild(view2);

}

 

After it is loaded, I run 2 commands from the console, the second command throws an error.

myInvoice.paymentMethod = null

myInvoice.paymentMethod = myPaymentMethod

 

Note that there are 2 views, one of which doesn't - collection, it gives no errors, and the other one is with a collection, this is the one that errors.

 

As a workaround I just added a condition to check if this.anchor.parentNode is not null to Serenade.js

 

Please, advise.

Jonas Nicklas

unread,
Jul 17, 2012, 5:50:10 AM7/17/12
to seren...@googlegroups.com
That sounds like a bug to me. Do you think you could write a failing
spec for this?

/Jonas

Kirill Grishin

unread,
Jul 17, 2012, 10:34:08 AM7/17/12
to seren...@googlegroups.com
I'll try to do that (believe it or not I've just started using unit testing)!

Kirill Grishin

unread,
Jul 18, 2012, 4:40:03 AM7/18/12
to seren...@googlegroups.com
Here is my JavaScript test for this issue:

describe(
  "Rendering of views with objects which have nested objects which have collection of nested objects",
  function(){
    it (
      "renders a view after a property which takes an object with a collection of other \
       objects is, first set to an object, then is set to null, then is set back to an object",
       function(){

        // This a class with which the view is built; it contains an instance of ObjectWithCollction in objectWithCollction
        var ContainerObject = Serenade.Model.extend('ContainerObject');
            ContainerObject.property('objectWithCollction');
           
        // This class contains a collection of CollectionItem instances
        var ObjectWithCollction = Serenade.Model.extend('ObjectWithCollction');
            ObjectWithCollction.hasMany('collectionItems', {
                as: function() { return CollectionItem }
            });
           
        // This class represents a collection item
        var CollectionItem = Serenade.Model.extend('CollectionItem');
            CollectionItem.property('value');
           
        var myContainerObject = new ContainerObject();
       
        var myObjectWithCollction = new ObjectWithCollction(
            {
                collectionItems: [
                    {value: 'one'},
                    {value: 'two'},
                    {value: 'three'},
                ]
            }
        );

        myContainerObject.objectWithCollction = myObjectWithCollction;

Serenade.view('viewWithCollection', '\
ul\n\
  - in @objectWithCollction\n\
    - collection @collectionItems\n\
      li @value\n\
');
        // Render the view
        var view = Serenade.render('viewWithCollection',myContainerObject);
       
        // 1st assertion       
        // Now this view should be a ul element with 3 li elements nested into it               
        expect(view.getElementsByTagName('li').length).toEqual(3);
       
        // Set myContainerObject.objectWithCollction to null,
        myContainerObject.objectWithCollction = null;
        // 2nd assertion
        // Now ul element should not contain any li elements
        expect(view.getElementsByTagName('li').length).toEqual(0);
       
        // Now assign myObjectWithCollction back to myContainerObject.objectWithCollction
        myContainerObject.objectWithCollction = myObjectWithCollction;
        // 3rd assertion
        // Expect ul element to contain 3 li children again
        expect(view.getElementsByTagName('li').length).toEqual(3);
       }   
    )
  }
)


Kirill Grishin

unread,
Jul 18, 2012, 4:45:09 AM7/18/12
to seren...@googlegroups.com
I can raise an issue and attach the spec to it on Github. Should I?

Jonas Nicklas

unread,
Jul 18, 2012, 7:12:45 AM7/18/12
to seren...@googlegroups.com
Sounds good. The Serenade specs are written in CoffeeScript though.
Check out the other specs to see how they are written.

/Jonas
Reply all
Reply to author
Forward
0 new messages