Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.


Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, biapar, Willr, Ingo, simon_w

Updating MemberTableField on save

Go to End

11 Posts   5215 Views

Nathan Cox

22 July 2007 at 4:36pm Community Member, 99 Posts


In a site I'm working on I have a page type that has_one member group. In the page's getCMSFields() I'm using a MemberTableField to let the user add members to that page's group.

I want it to work like an ImageField, so when you create a new page it displays a message telling you to save before you can edit the group, which is replaced by the MemberTableField subform when you save a draft.

The problem is I can't get it to load the form when the page is saved. I've tried using FormResponse::update_dom_id() in the page's onBeforeWrite() but I can't figure out how to get the actually HTML for the form...using $MemberTableField->renderWith('MemberTableField') causes errors, and anything else prints either "(none)" or "MemberTableField".
The only way I can get it to display is by refreshing the page (so it's created by getCMSFields()), which is just an extra hassle for the user.

Does this make sense? Has anybody else done something like this before that could help me out?


23 July 2007 at 1:44am (Last edited: 23 July 2007 1:47am), Google Summer of Code Hacker, 222 Posts

Hi Nathan,

> $MemberTableField->renderWith('MemberTableField') causes errors, and anything else prints either "(none)" or "MemberTableField".

I ran into this problem when I was working on making the Recipients tab in a Newsletter Mailing List get reloaded after new Recipients were imported.

I ended up using this in cms/code/NewsletterAdmin.php (comments added):

    * Reloads the list of recipients via ajax
   function getrecipientslist() {
      if( $_REQUEST['ajax'] ) {
         $newsletterType = DataObject::get_by_id('NewsletterType', $this->urlParams['ID'] );
         $fields = new FieldSet($memberList = new MemberTableField($this, "Recipients", $newsletterType->Group() ));
         // These 3 lines seem to be required to prevent fatal errors
         $actions = new FieldSet(new FormAction('save','Save'));
         $form = new Form($this, "EditForm", $fields, $actions);
         return $memberList->FieldHolder();
         // Instead of the above line which calls
         // ComplexTableField->FieldHolder() in sapphire/forms/ComplexTableField.php,
         // you can use the 2 lines below to use a custom template for
         // the MemberTable Field
         // $memberList->sourceItems();
         // return $memberList->renderWith('MemberTableFieldtemptest');

Then in cms/javascript/NewsletterAdmin_right.js I used this Javascript to get the "response.responseText" and use it to update the list:

function reloadRecipientsList() {

   var id = $('Form_EditForm_ID').value;

    var request = new Ajax.Request(baseHref() + 'admin/newsletter/getrecipientslist/' + id + '?ajax=1', {
      onSuccess: function( response ) {
         $('Root_Recipients').innerHTML = response.responseText;
         Behaviour.apply( $('MemberList') );
      onFailure: function(response) {
         statusMessage('Could not automatically refresh recipients list', 'bad');

I hope this helps. Let me know if you run into any problems and I'll be glad to try and help. :)

Have a great Sunday,

Elijah Lofgren

Nathan Cox

23 July 2007 at 4:10pm Community Member, 99 Posts

Thanks, you're a legend...problem is it's still not entirely working.

I've got the form appearing now (thanks!), but it won't do anything. I fill in a user's details and click 'Add' and nothing happens. Firebug says no AJAX happened.
I'm guessing the problem is that the javascript isn't getting applied...I don't really know Prototype of Behaviour at all, but I wonder if Behaviour.apply() doesn't work because the element didn't exist before - there was just a ReadonlyField telling you to save first.

What javascript do I need to say "apply this JS object to this bit"? The code that I THINK does it normally (in MemberTableField.js) is

MemberTableField.applyTo('#Form_EditForm div.MemberTableField');

but if I use that, it just tells me MemberTableField is undefined...


24 July 2007 at 5:37am Google Summer of Code Hacker, 222 Posts

Hi Nathan,

You've helped me discover a bug! ;)

My reloadRecipientsList() function is broken.

The add button does not work after it is called.

I get "FATAL ERROR: Object::__call() Method 'addtogroup' not found in class 'Form'
At line 159 in /var/www/silverstripe-gsoc/sapphire/core/Object.php"

It seems that it's not working to apply behaviour to stuff put in inner HTML.

I will work on fixing this after lunch and let you know of the outcome.




24 July 2007 at 6:19am Google Summer of Code Hacker, 222 Posts

Ok, this is strange. It seems to work perfectly after making this change:

Index: cms/javascript/NewsletterAdmin_right.js
--- cms/javascript/NewsletterAdmin_right.js (revision 39154)
+++ cms/javascript/NewsletterAdmin_right.js (working copy)
@@ -482,7 +482,7 @@

var request = new Ajax.Request(baseHref() + 'admin/newsletter/getrecipientslist/' + id + '?ajax=1', {
onSuccess: function( response ) {
- $('Root_Recipients').innerHTML = response.responseText;
+ $('Root_Recipients').outerHTML = response.responseText;
Behaviour.apply( $('MemberList') );
onFailure: function(response) {

Time for me to go read up on the differences between innerHTML and outerHTML. ;)


24 July 2007 at 9:51am Google Summer of Code Hacker, 222 Posts

As noted on [url=]What are innerText, outerText, innerHTML and outerHTML?[/url]
and Andy in #silverstripe today:

16:24 <@ajoneil> outerHTML replaces the whole content of that node, including its start and
end tags
16:24 <@ajoneil> innerHTML leaves the start and end tags alone

I also found that [url=]The jsenv bookmarklet is an even greater Debugging Tool than I thought it was[/url].

I was able to use the Firebug console in the jsenv window to see the error as shown in the attached screenshot:

I've currently looking at the diff of HTML generated by the "View Generated Source" option of the Firefox Web Developer extension to see if I can see what's happening with the HMTL, but I think the "this.parentNode has no properties
Line 119" error will probably provide the clue for why it doesn't work with




24 July 2007 at 10:57am (Last edited: 24 July 2007 11:10am), Google Summer of Code Hacker, 222 Posts

Could it be that using innerHTML makes parentnode get lost which makes 'this.parentNode has no properties' error about this line: var data = this.parentNode.parentNode.getElementsByTagName('input');?

Just as I was about to give up on trying find out why: Aha! I saw extra newlines in the diffs, but I didn't think they were important:
1. [url=]Rewriting content with Javascript[/url]: "This works in Safari and Internet Explorer, but encounters a bug in Firefox. In particular, each time the content is replaced via innerHTML, an additional newline (vertical whitespace) is inserted into the document. ... With a shallow clone and the innerHTML technique, we avoid the newline bug in Firefox and Mozilla. Further, we can allow rich markup in our replacement fragments."
2. [url=]Cleaning useless whitespace in Mozilla DOM[/url]: "Now, from my preliminary testing, this method doesn't remove visibly intruding textNodes like the functions in this post do, but any reference you make (firstChild, parentNode, etc) after enacting normalize() will grab the expected node, and not any intermediary textNode. "
3. [url=]Bug: Mozilla reports existence of phantom text nodes in the DOM[/url]
4. [url=]Whitespace in the DOM - MDC[/url]

Time to try some stuff! ;)


24 July 2007 at 11:31am Google Summer of Code Hacker, 222 Posts

I give up. I'm going to test that outerHTML works in IE6, IE7, and Safari 3 and just use that if it does. ;)

Go to Top