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.

DataObjectManager Module /

Discuss the DataObjectManager module, and the related ImageGallery module.

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

Dynamic dropdown field in DOM


Go to End


16 Posts   9006 Views

Avatar
Bright Eyes David

Community Member, 26 Posts

10 February 2011 at 12:33pm

I'd like to incorporate a "Type" (as in a section or a category) dropdown menu field which is dynamically populated with the entries of a DataObject called "PartType" into my DataObjectManager popup which is handling the "Part" DataObject.

Both Part and PartType are DataObjects. Can DOM handle this?

Many thanks.

Avatar
tmkp

Community Member, 42 Posts

10 February 2011 at 1:24pm

Edited: 10/02/2011 1:35pm

Hi David,

not 100% sure if this is what you looking for, but I'll give it a shot anyway.

This is a basic setup for a Discography Catalogue. Every DiscoRecord has a DiscoCategory, both are Dataobjects, and you can select the DiscoCategory in the DiscoRecord DOM Popup via dropdown.

You could set up a new page type ("DiscoPage") with two DOMs in seperate tabs for each the records and the categories,and the "Category" dropdown in the DiscoRecord DOM popup will populate dynamically.

<?php

class DiscoCategory extends DataObject {

	static $db = array(
	  "Title" => "Varchar(255)",
	);

	static $has_one = array (
		'Holder' => 'DiscoPage',
	);

	static $has_many = array (
		'Records' => 'DiscoRecord',
	);

	function getCMSFields() {
		$f = new FieldSet();
		$f->push( new TextField( 'Title', 'Title') );
		return $f;
	}

}

<?php

class DiscoRecord extends DataObject {

	static $db = array(
	  "Title" => "Varchar(255)",
	);

	static $has_one = array (
		'Holder' => 'DiscoPage',
		'Category' => 'DiscoCategory',
	);

	function getCMSFields() {
		$f = new FieldSet();

		// build dropdown menu for category selection
		$oData = (DataObject::get('DiscoCategory'));
		if ($oData) $CategoriesSource = $oData->toDropDownMap('ID','Title');
		$dropdown = new DropdownField('CategoryID', 'Category', $CategoriesSource, $this->CategoryID);
		$f->push ( $dropdown );

		// record detail fields
		$f->push( new TextField( 'Title', 'Title') );

		return $f;
	}

}

Note that in this example ALL DiscoCategory Dataobjects will be pulled into the dropdown, you might want to add a WHERE clause to (DataObject::get('DiscoCategory')); to make sure you're getting only the ones associated with your Holder Page.

Hope this helps!

Avatar
Bright Eyes David

Community Member, 26 Posts

10 February 2011 at 3:53pm

That's great tmkp - thanks!

I have a couple of follow on queries:

1) I found that I had to access the DiscoPage without the DiscoRecord DOM once in order to add a DiscoCategory to avoid the following error:

ERROR [Notice]: Undefined variable: CategoriesSource
IN POST /admin/getitem?ID=19&ajax=1
Line 20 in [...]/mysite/code/DiscoRecord.php

It's not likely to be a problem, but I wondered if there was a way to cater for this event?

2) Is it possible to show the chosen DiscoCategory for each Record on the DiscoRecord DOM tab, and to filter by it?

Avatar
tmkp

Community Member, 42 Posts

11 February 2011 at 12:00am

Edited: 11/02/2011 12:18am

Hi again,

to make the DiscoRecord DOM show the selected Category for each Record put this in your DiscoPage

...
		/*********************************
		/* SET UP RECORDS MANAGER
		/*********************************/
		$mng_records = new DataObjectManager(
			$this, // Controller
			'Records', // Source name
			'DiscoRecord', // Source class
			array(
					'Title' => 'Title',
					'Category.Title' => 'Category',
			),
			'getCMSFields_forPopup',
		);

		$f->addFieldToTab("Root.Content.Records",$mng_records);
...

Back in the days when i tinkered around with this, sorting by related fields was not supported by DOM, but I think filtering might be feasible.

As to that error, try extending the if clause to wrap up the whole dropdown constructor like so

// build dropdown menu for category selection
$oData = (DataObject::get('DiscoCategory'));

if ($oData) {
	$CategoriesSource = $oData->toDropDownMap('ID','Title');
	$dropdown = new DropdownField('CategoryID', 'Category', $CategoriesSource, $this->CategoryID);
	$f->push ( $dropdown );
} else {
	// no categories there yet, might put a literalfield to tell the user
}

Otherwise Silverstripe might try to create a dropdown from an empty variable if there are no categories present.

Avatar
Bright Eyes David

Community Member, 26 Posts

11 February 2011 at 3:26pm

I see - thanks! Working a treat now.

The filtering doesn't seem to work on the category from within the record DOM. I've tried both "Category" and "Category.Title", but neither work.

		$mng_records->setFilter(
			'Category.Title', // The field we're filtering
			'Filter by Category', // The label for the filter field
			array(
				'asdf' => 'asdf',
				'qwer' => 'qwer'
			) // The dropdown map of values => display text. The values will be matched against the field.
		);

This is more of a want than a need at this stage, though.

Thanks again!

Avatar
tmkp

Community Member, 42 Posts

11 February 2011 at 10:49pm

Edited: 11/02/2011 11:17pm

Hi David,

glad I could help. Try this for the filter

		// Filter By Category Setup
		// only display the filter if there are categories present
		if ($oData = $this->Categories()) {
			$CategoriesSource = $oData->toDropDownMap('ID','Title');
			$mng_records->setFilter(
				'CategoryID', // The field we're filtering
				'Filter by Category', // The label for the filter field
				$CategoriesSource // The dropdown map of values
			);
		}

It seems to work alright over here, although i did not check for pagination and PageSize support

----------- EDIT: -----------

This would go into your Holder Page.

The if clause (green bit) again will ensure that the filter only shows up if there are any categories associated with your holder page. I'm using the syntax that is documented here to get the Dataobjects from the $has_many, but you could also use the standard DataObject::get method with HolderID=$this->ID in the WHERE clause. Just looks better that way : )

----------- EDIT 2: -----------

Just played around with this some more and realized that if you add a new category in the Category DOM, the Category filter dropdown in the Record DOM will not automatically update itself. Not exactly sure how to go about this.. Hitting "refresh" next to Filter by Category will make the new Categories show up though.

Avatar
tmkp

Community Member, 42 Posts

12 February 2011 at 1:11am

Just trying out some new things here..

Say for instance, if you want to have the number of associated Records show up in your Category filter dropdown, you can use a custom getter as described here.

Just put this in your DiscoCategory

	function getDropdownSummary() {
		$String = $this->Title . " (" . $this->Records()->TotalItems() . ")";
		return $String;
	}

And in your HolderPage Records DOM change your filter dropdown source to

		$CategoriesSource = $oData->toDropDownMap('ID','DropdownSummary');

Avatar
tmkp

Community Member, 42 Posts

12 February 2011 at 2:58am

And hello once again,

I'll post the complete code here for future reference. It's a working example with lots of room for improvement, but it's got the basic functionality covered. I'm getting no more errors when trying to create a new Record when there are no Categories, and it seems fairly stable, with filters, pagination and pagesize all working as expected.

DiscoHolder.php

<?php

class DiscoHolder extends Page {

	static $has_many = array (
		'Records' => 'DiscoRecord',
		'Categories' => 'DiscoCategory',
	);

	public function getCMSFields() {
		$f = parent::getCMSFields();

		/*********************************
		/* SET UP RECORDS MANAGER
		/*********************************/
		$mng_records = new DataObjectManager(
			$this, // Controller
			'Records', // Source name
			'DiscoRecord', // Source class
			array(
					'Title' => 'Title',
					'Category.Title' => 'Category',
			),
			'getCMSFields_forPopup'
		);

		// Filter By Category Setup
		// only display the filter if there are categories present
		if ($oData = $this->Categories()) {
			$CategoriesSource = $oData->toDropDownMap('ID','DropdownSummary');
			$mng_records->setFilter(
				'CategoryID', // The field we're filtering
				'Filter by Category', // The label for the filter field
				$CategoriesSource // The dropdown map of values => display text. The values will be matched against the field.
			);
		}

		$f->addFieldToTab("Root.Content.Records",$mng_records);

		/*********************************
		/* SET UP CATEGORY MANAGER
		/*********************************/
		$mng_cats = new DataObjectManager(
			$this, // Controller
			'Categories', // Source name
			'DiscoCategory', // Source class
			array(
					'Title' => 'Title',
			),
			'getCMSFields_forPopup'
		);

		$f->addFieldToTab("Root.Content.Categories",$mng_cats);

		// return the cms fields
		return $f;
	}

}

class DiscoHolder_Controller extends Page_Controller {

}

DiscoRecord.php

<?php

class DiscoRecord extends DataObject {

	static $db = array(
		"Title" => "Varchar(255)"
	);

	static $has_one = array (
		'Holder' => 'DiscoHolder',
		'Category' => 'DiscoCategory'
	);

	function getCMSFields_forPopup() {
	
		$f = new FieldSet();

		// build dropdown menu for category selection
		$myholder = $this->Holder()->ID;
		$oData = DataObject::get("DiscoCategory", "HolderID = '$myholder'");

		// but only show the dropdown if there are any categories associated with the holder page
		if ($oData) {
			$CategoriesSource = $oData->toDropDownMap('ID','Title');
			$dropdown = new DropdownField('CategoryID', 'Category', $CategoriesSource, $this->CategoryID);
			$f->push ( $dropdown );
		}
		
		// record detail fields
		$f->push( new TextField('Title','Title') );
		
		return $f;
		
	}

}

DiscoCategory.php

<?php

class DiscoCategory extends DataObject {

	static $db = array(
		"Title" => "Varchar(255)"
	);

	static $has_one = array (
		'Holder' => 'DiscoHolder'
	);
	
	static $has_many = array (
		'Records' => 'DiscoRecord'
	);
	
	function getCMSFields_forPopup() {
		$f = new FieldSet();
		$f->push( new TextField( 'Title', 'Title') );
		return $f;
	}

	function getDropdownSummary() {
		$String = $this->Title . " (" . $this->Records()->TotalItems() . ")";
		return $String;
	}

}

Schönes Wochenende!

Andi

Go to Top