-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Build an element in steps #4
Comments
Hi Mike, glad you're finding our libraries and making use of them. Ok, so what you're trying to do is essentially the bread and butter of the Tagged library. A So, where above you have instantiated a $anchor = Html::tag('a.timeOfDay-class', [
'attribute' => 'value'
]);
echo $anchor->open();
echo 'Some content from somewhere else';
echo $anchor->close(); The much more common approach is to use the echo Html::{'a.timeOfDay-class'}('My content', [
'data-environment' => $is_daytime ? 'sunlight' : 'starlight
]); Or, you could do it more programatically, depending on your code context: $anchor = Html::a(null);
$anchor->addClass('timeOfDay-class');
$anchor->setBody('My content');
if ($is_daytime){
$anchor->setDataAttribute('environment', 'sunlight');
} else {
$anchor->setDataAttribute('environment', 'starlight');
}
echo $anchor; Also note, that because the Hope that helps, let me know if you need any more help. |
Awesome. I wasn't familiar with Collections (and am still not quite there). I see that Element is an interface, but can you point me to where the |
Hi Mike. The setBody method is defined in the ElementTrait trait in the Elemental package, here - https://github.com/decodelabs/elementary Elemental defines a generic set of tag and element constructs, and Tagged is the HTML implementation of that interface. (Another package, Exemplar, also defines an XML implementation too) ElementTrait defines a few helpers like setBody, etc, then the rest of the container controls are in the Collections package. The Collections package contains a number of classes used for containing sets of things in different ways - you can think of a Sequence as a php array with only numerical indexes and the equivalent of the php array_* functions available on the object. |
Still feeling a little slow on the uptake here, @betterthanclay and much appreciating your patience. I want to build an HTML table from an array. So I need something like this:
Does this looks like the approach the tool has in mind (so to speak): $table = Html::{'table'}(null);
foreach ( $horizontal_schedule as $day => $classes ) :
$thead = Html::{'thead'}( Html::{'tr'}(null) );
$thead->append(Html::{'th'}( gmdate( get_option( 'date_format' ), strtotime( $day ) ) ));
$thead->append(Html::{'th'}( 'Class Name' ));
$table->append($thead);
foreach ( $classes as $k => $class ) :
$table->append(Html::{'tr'}(Html::{'td'}( $class->class_name )));
endforeach;
endforeach;
$result->append($table); |
Hi Mike. I'm not completely sure what table structure you're trying to make here - are you trying to create multiple tables, one for each day in I'm going to take a guess that you're aiming for one table and this is roughly the structure you're looking for: <table>
<thead>
<tr>
<th>Day 1</th>
<th>Day 2</th>
<th>Day 3</th>
<th>Day 4</th>
...
</tr>
<thead>
<tbody>
<tr>
<td>Class 1 for day 1</td>
<td>Class 1 for day 2</td>
<td>Class 1 for day 3</td>
<td>Class 1 for day 4</td>
...
</tr>
<tr>
<td>Class 2 for day 1</td>
<td>Class 2 for day 2</td>
<td>Class 2 for day 3</td>
<td>Class 2 for day 4</td>
...
</tr>
<tr>
<td>Class 3 for day 1</td>
<td>Class 3 for day 2</td>
<td>Class 3 for day 3</td>
<td>Class 3 for day 4</td>
...
</tr>
</tbody>
</table> Which would look like this:
If that's the case, the code to generate it would ideally look like this.. it's a little more fiddly than usual because your data appears to be stored as columns not rows: // Element body can be rendered in a generator closure using yield statements
echo Html::table(function() use($horizontal_schedule) {
// Generate header
// Use list macro to create elements (th) with a loop ($horizontal_schedule) in a container (nested, thead > tr)
yield Html::list($horizontal_schedule, 'thead > tr', 'th', function($classes, $thElem, $day) {
return gmdate( get_option( 'date_format' ), strtotime( $day ) );
});
// Extract list of $classes keys to generate rows
// Assumes all $classes lists are the same length
$classes_keys = array_keys($horizontal_schedule[array_key_first($horizontal_schedule)]);
// Generate body
// Loop over keys (rows), create tbody container with child tr elements
yield Html::list($classes_keys, 'tbody', 'tr', function($key) use($horizontal_schedule) {
// Loop through days for each row
foreach($horizontal_schedule as $day => $classes) {
// Create cell for each class name
yield Html::td($classes[$key]->class_name);
}
});
}); Alternatively, if you are just trying to create a single-column table for each day, then it's much simpler.. I'm just not sure how useful this actually is: echo Html::elements($horizontal_schedule, 'table', function($classes, $table, $day) {
yield Html::{'thead > tr th'}(gmdate( get_option( 'date_format' ), strtotime( $day ) ));
yield Html::list($classes, 'tbody', 'tr > td', function($class) {
return $class->class_name;
});
}); Which creates:
etc.. Hope that helps - if you can let me know exactly what HTML you're trying to create, I can show you how to make it with Tagged and hopefully you'll get the hang of making your own structures from there. |
Really elegant and insightful, man. I love the utilization of generators. The list method is challenging me a bit, and generally you are raising the bar in terms of my coding so thank you. Perhaps I can contribute at least to the docs in some of this beautiful tool set. I may want to include two HTML elements in each TH, which I see I can also do naively like this: yield Html::list($horizontal_schedule, 'thead > tr', 'th', function($classes, $thElem, $day) {
$timefromstring = strtotime($day);
return Html::h3(gmdate( 'l', $timefromstring ))->append(Html::h5(gmdate( 'F jS', $timefromstring )));
}); Again, that feels like the hack and slay approach. What would a wizard do? |
Hi Mike. Ok, so for reference there are a handful of looping helper macros available: list()This lets you create a container element, loop over your iterable, and create child elements within the container: Html::list($iterable, 'container-element', 'child-element', function($value, $childElement, $key) {
// Generate content here
yield Html::span(['Key: ', $key]);
yield Html::span(['Value: ', $value]);
}); This would make something like: <container-element>
<child-element>
<span>Key: 0</span>
<span>Value: value 1</span>
</child-element>
<child-element>
<span>Key: 1</span>
<span>Value: value 2</span>
</child-element>
<child-element>
<span>Key: 2</span>
<span>Value: value 3</span>
</child-element>
</container-element> elements()The same as list, but without the container: Html::elements($iterable, 'child-element', function($value, $childElement, $key) {
// Generate content here
yield Html::span(['Key: ', $key]);
yield Html::span(['Value: ', $value]);
}); Would make something like: <child-element>
<span>Key: 0</span>
<span>Value: value 1</span>
</child-element>
<child-element>
<span>Key: 1</span>
<span>Value: value 2</span>
</child-element>
<child-element>
<span>Key: 2</span>
<span>Value: value 3</span>
</child-element> uList() / oList()Wrapper around list to create ul and ol elements: Html::uList($iterable, function($value, $liElement, $key) {
// Generate content here
yield Html::span(['Key: ', $key]);
yield Html::span(['Value: ', $value]);
}); Would make something like: <ul>
<li>
<span>Key: 0</span>
<span>Value: value 1</span>
</li>
<li>
<span>Key: 1</span>
<span>Value: value 2</span>
</li>
<li>
<span>Key: 2</span>
<span>Value: value 3</span>
</li>
</ul> In your example above, the yield Html::list($horizontal_schedule, 'thead > tr', 'th', function($classes, $thElem, $day) {
$timefromstring = strtotime($day);
yield Html::h3(gmdate( 'l', $timefromstring ));
yield Html::h5(gmdate( 'F jS', $timefromstring ));
}); However, we can also go one step further and use the date helper in Tagged like this: yield Html::list($horizontal_schedule, 'thead > tr', 'th', function($classes, $thElem, $day) {
yield Html::h3(Html::$time->format('l', $day));
yield Html::h5(Html::$time->format( 'F jS', $day));
}); |
Cool! From Python (I now know, incorrectly) I had understood a FWIW, the
Producing
|
Hi Mike. Interesting - I'm not really sure how that can be the case as when you append, any items you pass it will go into the body collection which will always be rendered inside the tags. The closing tag is always the last thing to be rendered in any particular element. It may be the I've just tested to make sure: echo Html::div(function () {
return Html::h3('First')->append(Html::h4('Second'));
}); Results in the following (h4 inside h3): <div>
<h3>
First<h4>Second</h4>
</h3>
</div> Anyway, for the most part, using And yeah, it's worth wrapping your head around how generators generally work in PHP as they can be confusing unless you have the background to them. In the case of Tagged, it's set up so you can essentially use |
I bet the Chrome dev tools was "fixing" those nested heading tags for me. Should have checked the source HTML. My (mentor and) colleague has a little lightweight JS library that works very similarly to Tagged: https://github.com/Rosuav/choc Have a nice one, Tom. |
Yeah, more than likely actually. Can make it a bit confusing in situations like this where you're not actually looking at what you're producing from the server. Thanks for the link, I'll check out choc. |
One thing I came across today that perhaps you would suggest an yield Html::{'select#location'}(function() {
foreach(Engine\Credentials::$site_ids as $k => $locID){
yield Html::option(Engine\Credentials::$site_names[$k], ['value' => $locID'']);
}
}); Additionally, how do I add a keyless attribute like $selected = ($locID == $_SESSION['region']) ? 'selected' : '';
yield Html::option(Engine\Credentials::$mbo_site_names[$k], ['value' => $locID, 'selected' => $selected]); 'Cause if I recall correctly, "selected" is the same as "selected=selected". TY |
Hi Mike. Sure - this should do the job: yield Html::list(Engine\Credentials::$site_ids, 'select#location', 'option', function($locID, $option, $k) {
$option
->setAttribute('value', $locID)
->setAttribute('selected', $locID == $_SESSION['region']);
return Engine\Credentials::$mbo_site_names[$k];
}); Keyless attributes are treated as boolean in HTML / JS, and Tagged does the same - use true or false to include or not include those attributes. In this case, the check against |
Hi. Discovering this through WPBP and it looks pretty sweet!
I'm wanting to build an element in steps and it looks like the Tag methods are the way to do that.
What I'm hoping you can tell me is how to add the Content, dynamically.
The text was updated successfully, but these errors were encountered: