tags:

views:

807

answers:

2

Hi all,

I just ran into this building a Textbox control for my MVC framework, where just before finalizing the whole document I call PreRender on everything that inherits from ServerTag (which in turn inherits from DOMElement).

The only way i have found to change a DOMElement derived object's tagName is to replace it with a new one with all the attributes synced to the old one.

This is how that looks in code:

protected function PreRenderTextarea( WebPage $sender )
{
    $textarea = $sender->createElement( 'textarea' );
    foreach( $this->attributes as $attribute )
    {
        if ( $attribute->name == 'value' )
        {
            $textarea->nodeValue = $attribute->value;
        }
        else
        {
            $textarea->setAttribute( $attribute->name, $attribute->value );
        }
    }
    $this->parentNode->replaceChild( $textarea, $this );
}

public function OnPreRender( WebPage $sender )
{
    parent::OnPreRender();
    $this->setAttribute( 'value', $this->Value );

    switch( $this->Mode )
    {
        case 'normal' : 
            $this->setAttribute( 'type', 'text' ); 
            break;
        case 'password' : 
            $this->setAttribute( 'type', 'password' ); 
            break;
        case 'multiline' : 
            $this->PreRenderTextarea( $sender ); 
            return; 
            break;
    }
}

Is that really the only way to do it? This way has the rather unwanted side effect of nulling all the logic behind the control.

+1  A: 

Yes, this how you have to do it -- the reason is that you're not just changing the value of a single attribute (tagName), you're actually changing the entire element from one type to another. Properties such as tagName (or nodeName) and nodeType are read-only in the DOM and set when you create the element.

So, creating a new element and moving in place of the old one exactly as you're doing, with DOMNode::replaceChild, is the correct operation.

I'm not sure what you mean by "unwanted side effect of nulling all the logic behind the control" -- if you clarify I might be able to give you guidance there.

It sounds like you might not want to have ServerTag inherit from DOMElement and instead you may want to link these two objects through some other pattern, such as composition (i.e. so a ServerTag "has a" DOMElement instead of "is a" DOMElement) so that you're merely replacing the DOMElement object associated with your ServerTag Textbox object.

Or a longer-shot guess is you might be running into issues just copying the attributes (i.e. textarea has required attributes, like rows and cols, that input does not).

joelhardi
That's pretty much what i figured out, even though i don't think it should work that way
Kris
A: 

I just found out that this all is possible in .NET when inheriting from XmlElement, so the whole php being unable to do it cleanly bugs me just a little bit more now.

Kris