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.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Archive /

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

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

Updating MemberTableField on save


Go to End


11 Posts   6579 Views

Avatar
Nathan Cox

Community Member, 99 Posts

22 July 2007 at 4:36pm

Hi,

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?

Avatar
elijahlofgren

Google Summer of Code Hacker, 222 Posts

23 July 2007 at 1:44am

Edited: 23/07/2007 1:47am

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
			$memberList->setController($this);
			$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

Avatar
Nathan Cox

Community Member, 99 Posts

23 July 2007 at 4:10pm

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...

Avatar
elijahlofgren

Google Summer of Code Hacker, 222 Posts

24 July 2007 at 5:37am

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.

Cheers,

Elijah

Avatar
elijahlofgren

Google Summer of Code Hacker, 222 Posts

24 July 2007 at 6:19am

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. ;)

Avatar
elijahlofgren

Google Summer of Code Hacker, 222 Posts

24 July 2007 at 9:51am

As noted on What are innerText, outerText, innerHTML and outerHTML?
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 The jsenv bookmarklet is an even greater Debugging Tool than I thought it was.

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
http://localhost/silverstripe-gsoc/cms/javascript/MemberTableField.js
Line 119" error will probably provide the clue for why it doesn't work with 
innerHTML.

Cheers,

Elijah

Avatar
elijahlofgren

Google Summer of Code Hacker, 222 Posts

24 July 2007 at 10:57am

Edited: 24/07/2007 11:10am

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. Rewriting content with Javascript: "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. Cleaning useless whitespace in Mozilla DOM: "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. Bug: Mozilla reports existence of phantom text nodes in the DOM
4. Whitespace in the DOM - MDC

Time to try some stuff! ;)

Avatar
elijahlofgren

Google Summer of Code Hacker, 222 Posts

24 July 2007 at 11:31am

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