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.

Template Questions /

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

renderWith() and Object iteration in Template


Go to End


4 Posts   2937 Views

Avatar
Jakxnz

Community Member, 36 Posts

15 January 2012 at 11:32pm

Edited: 15/01/2012 11:32pm

Hey crew,

This question will be exposing some serious holes in my knowledge of programming. But here we go:

I have a custom class that extends Veiwable data and has a forTemplate() method to render the class.

Question 1: When I iterate through my set of these classes in a template, what is the best method to reference the Objects (of my class) so that it renders with my Template?

Question 2: What is the best Data type to reference my set as? At the moment I'm using DataObjectSet

Examples:

Class MyData.php:

class MyData extends ViewableData {

. . .

	function forTemplate() {
		return $this->renderWith(array(
			$this->class,
			'MyData'
		));
	}

. . .

}

Class Page_Controller:


. . .

function getMyDataSet() {
	return new DataObjectSet($myDataInstances);
} 

. . .

Page Template:


<% control MyDataSet %>

	errr... what do I reference my Object and render it with it's template via?

<% end_control %>

----------------------------------------------------

My current solution is to do something like this:

Class MyData.php:

class MyData extends ViewableData {

. . .

	function getDataRenderedWithTemplate() {
		return $this;	
	}

. . .

}

Page Template:


<% control MyDataSet %>

	$DataRenderedWithTemplate

<% end_control %>

Avatar
juergr

Community Member, 17 Posts

16 January 2012 at 12:57am

Edited: 16/01/2012 1:04am

Hey jdi!

I don't know if i understand your question right, but i've solved quit the same problem just a few days ago. But it seems to me that you have to write a new class, which just handles the rendering of your DataObject, so you dont have to write for each object a "renderWithSpecialTemplate"-function.

What if've wanted to do: Create a simple class to generate jQuery Accordion elements (see: http://jqueryui.com/demos/accordion/)

So basicaly i've created a class which holds a whole Accordion and another class which holds a single Accordion Item.
Lets start with the Accordion class:

class Accordion extends UIElement {
    private $items; // DataObjectSet with Accordion_item's
    private $item_template = 'Accordion_item';
    private $template = 'Accordion';
    private $ID;

    public function  __construct($items, $name = null, $template = null, $itemTemplate = null) {
        $this->initialize($name);
        if($template != null) {
            $this->setTemplate($template);
        }
        if($itemTemplate != null) {
            $this->setItemTemplate($itemTemplate);
        }
        $this->setItems($items);
    }

    public function  initialize($id = null) {
        if($id != null) {
            $this->ID = $id;
        } else {
            $this->ID = uniqid();
        }
        Requirements::css('mysite/UIComponents/accordion/css/accordion.css');
        $this->includeJQueryUI();
        Requirements::customScript(<<<JS
                	$(function() {
                            $( "#accordion_{$this->ID}" ).accordion({
                                active: false,
                                animated: false
                            });
                        });
JS
                );
    }

    public function setItems($items) {
        $this->items = new DataObjectSet();
        foreach($items as $item) {
            $this->items->push(new Accordion_item($item,$this->item_template));
        }
    }

    public function setTemplate($template) {
        $this->template = $template;
    }

    public function setItemTemplate($template) {
        $this->item_template = $template;
    }

    public function forTemplate() {
        $data = array(
            'ID'    => $this->ID
        );
        return $this->customise($data)->renderWith(array($this->template));
    }

    public function Items() {
        return $this->items;
    }
}

I think this code is pretty self explaining. Accordion extends UIElement which is a ViewableData-class with some basic function like including jQuery.

Then we have the Items class (in the same file) which is straightforward and easy to understand:

class Accordion_item extends ViewableData {
    private $data;
    private $template;

    public function __construct($item, $template) {
        $this->setData($item);
        $this->setTemplate($template);
    }

    public function setData($data) {
        $this->data = $data;
    }
    
    public function setTemplate($template) {
        $this->template = $template;
    }

    public function Item() {
        return $this->data->renderWith(array($this->template));
    }
}

Then there are two templates default templates.
Accordion.ss

<% if Items %>
<div id="accordion_{$ID}">
    <% control Items %>
    $Item
    <% end_control %>
</div>
<% else %>
<p>No entries found!</p>
<% end_if %>

Accordion_item.ss

<h3><a href="#">$Title</a></h3>
    <div>
        $Content
    </div>

And this is how to use it:

        $items = DataObject::get('Tour', 'StartDatum > NOW()', 'StartDatum ASC', '', $count);
        $UI = new Accordion($items, 'NextTouren');

As a third and fourth argument of Accordion you can pass your own template. The second parameter is not required and defaults to a unique ID.

My code is still under developement and there are several things which can be improved. So any hints and ideas are welcome!

I hope this helps and have fun codding!

Avatar
MarcusDalgren

Community Member, 288 Posts

16 January 2012 at 3:51am

Why are you extending ViewableData directly and not using DataObject?

Avatar
juergr

Community Member, 17 Posts

16 January 2012 at 5:12am

Because I don't need the benefits of a DataObject such as storing any data in the DB or write/load from the DB. So i think its better to extend just ViewableData. All the displayed Data is passed to the Accordion class by passing a DataObjectSet to the constructor as first argument.

What would the benefits be if I extend from DataObject?