How to set only an offset when looping? - silverstripe

I have a situation where I need to start to loop through my images from the 7th image onwards e.g
// This shows the first 6 images
<% loop $GalleryImages.Limit(6) %>
<img src="$Image">
<% end_loop %>
--
Then I need to show from the 7th image on wards. We can use the offset here but we have to set a limit (first parameter)
<% loop $GalleryImages.Limit(100, 6) %>
<img src="$Image">
<% end_loop %>
Is there a way to just set the offset only or maybe another way I should tackle this?

The cleanest thing to do is to create a method in your controller or model that runs the query.
public function OtherGalleryImages()
{
return $this->GalleryImages()->limit(null, 6);
}
But I would question whether you really ever want to run an unlimited query, and for that reason, I think a simpler fix would be to just add a reasonable number into your limit on the template, as you have done. If you ever have more than 100, perhaps you have bigger problems than the expressiveness of your template syntax. :-)

PHP's array_slice method allows you to specify a start, without know the length of the array.
http://php.net/manual/en/function.array-slice.php
The advantage of using slice is that if the array is too short or too long, it will return an empty array instead of null, thus avoid errors

Related

optimization: vector.erase() of pointer

I have a question about deleting a dynamic vector of pointers and optimization.
Here is my code. It checks wether an element has to be set to nullptr and then it delete all those elements.
for (auto* el : elements)
{
if (el != 0)
// do something
else
el = nullptr;
}
elements.erase(std::remove(elements.begin(), elements.end(), nullptr), elements.end());
Is the complexity of this operation onerous for the machine ?
And if it is, then is there a better way of doing it and it is worth it ? Because, here, the preservation of the index order is not important for me.
Thank you !
Is the complexity of this operation onerous for the machine ?
It is a bit costly, but not much more than the previous operation. Indeed, remove will typically check the value of each item, and if an item needs to be removed, the algorithm shifts the item on the right to put it on the current analysed item. erase is often relatively cheap since it just resizes the vector to skip the remaining garbage at the end (generally without any copy or reallocation) and call the destructor of the discarded items (costly only if there is a lot of them and the destructor is non-trivial). This operation can be as costly as the previous one.
And if it is, then is there a better way of doing it and it is worth it ? Because, here, the preservation of the index order is not important for me.
Yes, this is possible: you can just iterate over the array with a classical loop and swap the current item with the one of the end to discard it. You need to maintain a end iterator moving from the end to the beginning. The loop stops when the end iterator is reached. Note that the swapped items coming from the end should be checked by your predicate too.
Alternatively, you could just use std::partition at this algorithm does a quite similar job and is simpler: it puts the items validating a given condition to the left part and put the other on the right part. You can then just resize the array to remove the unwanted right part.
std::partition should is bit less efficient than the other swap-based approach only if there is a lot of item to remove since it has to maintain the consistency of both sides.
Here is an (untested) example with std::partition:
auto discardedBegin = partition(elements.begin(), elements.end(), doSomething);
elements.erase(discardedBegin, elements.end());

How would I pass an array to a template as an attribute and then use the array, then use the template recursively?

I've been working with ColdFusion CFML for a few months after using JSP for several years and there are still some things I'm having trouble figuring out in this language. Google, CFDocs, and Adobe have been no help with this particular question.
I'm building a feature to display comments below an article, where a comment can also have child comments. I have all the data imported and it looks great. I'm using a query that returns an array of structs, it gets each first-level comment for the article and I loop back through that array and attach an array of structs to each comment-struct that has children.
I've written a template to loop through and display the list of first-level comments but I'd like it to call itself recursively on each comment that has child comments until it has displayed all of the child comments of each comment. I'd assume that the best way to accomplish this would be for the template to call itself while passing it the array of child comments.
I've read several articles that explain how to create a CFModule but NONE that say how to actually use the attribute that you pass it. Here's one of the things I've tried:
(in the original template):
<h4>Comments</h4>
<div id="comments" name="comments">
<cfmodule template="comments.cfm" comments="#Variables.page.comments#">
</div>
(in the template that I want to eventually call recursively):
<cfoutput>
<cfloop array = "#comments#" index = "comment">
<div>#comment.commenter_name# says</div>
<div>#comment.created#</div>
<div>#comment.content#</div>
</cfloop>
</cfoutput>
I can't just use Variables.page.comments in the second template because the template's going to call itself recursively; for instance, I'll want the array at Variables.page.comments[2].comments the next time, Variables.page.comments[2].comments[5].comments the time after, etc
You could generate your hierarchical view by wrapping your rendering logic around
<cfscript>
cfsavecontent variable="html" {
do logic stuff here
}
writeOutput(html);
<cfscript>
which will store your output into a variable. Then output the variable.
You could also write a recursive function to do it, and then simply output the returned string, like below. You might want to add some limit logic so you don't output the entire discussion at once, depending on how big the discussion are.
string function outputComments (
required array comments) {
var html = "";
for (var comment in arguments.comments) {
html &= "<li>#comment.message#";
if (comment.children.length) {
html &= outputComments(comment.children);
}
html &= "</li>";
}
if (html != "") {
html = "<ul>#html#</ul>";
}
return html;
}
writeOutput(outputComments(comments));
Having done a bunch of this kind of work, you may want to consider rendering your comments/replies in some sort of JavaScript ajax-driven widget, using a service that returns comments data in JSON, where you get a page of comments or replies at a time. I wrote a Facebook-style comment widget that worked that way, and the advantage is that you don't have to worry about conversation size.

Extending a Variable's Lifetime

To be fair, I cannot be entirely sure the title correctly describes the problem I am having, as it merely mirrors my current understanding of Ada as it is.
The Problem
I have a function:
function Make_Option (Title : String) return Access_Option is
O : aliased Option := (
Title_Len => Title'Length,
Title => Title);
begin -- Make_Option
return O'Unrestricted_Access;
end Make_Option;
This function is supposed to create a new menu option for the user, that may in turn be inserted into a menu (one that you might see in a terminal-based environment). You are all probably sighing, as quite evidently, the O variable would be deallocated at the end of this function (from my current understanding). As such, using the Unrestricted_Access here is just plain stupidity, but it mirrors the result of what it is I am trying to accomplish (as this code indeed does compile successfully).
The Access_Option is defined as following:
type Access_Option is access all Option;
The idea is that with an access to the option, which in turn is a discriminated record, is that we can store it within an array-like structure (as the object itself varies in size).
Beyond doubt, it would be nice if we could instead use the Access attribute for this, as the compiler would then make sure the lifetime is long enough of the O variable we are referencing, but as the lifetime as a matter of fact only exists til the end of the Make_Option function, we are presented with the following:
non-local pointer cannot point to local object
What I am then asking, is: how would I go about having a function to create Access_Options for me? Is such a thing even possible, or am I doing it all wrong? To clarify, what I am trying to do is create a neat way for filling an array with references to discriminated records, that I can then dereference and use.
Thought Process
I personally have not tried too many things, more than think about solutions that may be plausible for the problem. And, frankly, rather than going crazy of working makeshift solutions, it would be nice to have a solution that works for large-scale applications too, without messing up the code base to bad.
Would you perhaps have some sort of object queue to handle it? Does Ada even deallocate resources automatically in the first place? Gah. I am confused.
Would it, in fact, be possible to somehow place the O variable outside of the scope for deallocation to then manually deallocate it later?
Given the example you show above a much simpler approach is to simply make an array of Unbounded_String:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_Io;
procedure Str_Arrays is
type Arr is array(1..10) of Unbounded_String;
A : Arr;
begin
for S of A loop
S := To_Unbounded_String("Hello World!");
end loop;
for S of A loop
Put_Line(To_String(S));
end loop;
end Str_arrays;
Don't try that.
There are two alternative options:
1) Use Ada.Containers.Indefinite_Vectors instead of a plain array.
2) Give your record discriminant a default value. Then you can store it in a plain array.
You seem to be reinventing the bounded string. Alternatives include
Using an instantiation of Ada.Strings.Bounded.Generic_Bounded_Length
Using Ada.Strings.Unbounded
Using an indefinite container (Ada.Containers.Indefinite_*) to hold type String

Loop modulo condition with Handlebars.js

I am looping through objects using Handlebars. My issue is that there is no way I can easily add some code every x iterations (% 2 or % 3).
I tried the solution proposed on How can I create conditional row classes using Handlebars.js?. It doesn't work because I am using the framework called Meteor, and my "collection" is coming from a MongoDB query through Meteor. Using that solution, the "Context" is equal to the whole Meteor context and my collection is nowhere to be found...
My first idea was to create a new boolean property on my object called "eof" and a Handlebars condition would be triggered with some more code if it is equal to true... but I would like something cleaner and not dependent of the server-side.
How would you do it?
Thanks a lot!
See Tom Coleman's answer.
You could add a template helper that would look something like:
Template.tableWithDifferentColorRows.helpers({
modulo3: function() {
return (this.index % 3) === 0;
},
});
// in the html:
{{#each_with_index collection}}
<div {{#if modulo3}}style='color:purple'{{/if}}>
actual content...
</div>
{{/each}}

How to add a property to a map dynamically in velocity?

I have the following code
$pageName = "test";
$Container = {};
I like to set a property of $Container by a variable. I tried $Container.set("test", $pageName);. It didn't raise any errors, but $Container.test or $Container.get("test"); display nothing.
How do I fix it?
The problem is that set is the wrong method. You need to do a put. Remember - Velocity is calling the Java methods. There is no "set" method on a Map object.
Specifically, you can do
$Container.put("test", $pageName)
Now, one weird thing is that this will print "true" or "false" in the page, since the Map.put() method returns a boolean. So I always do
#set($dummy = $Container.put("test", $pageName))
which does the put and stores the result in another reference (which you can then ignore) instead of rendering it to the page.
Hey I ran into the same problem is the "true" or "false" printed on the page, and there is a simpler way to handle it. What I did is a little weird, and I did it Confluence, which of course uses Velocity under the covers. I mention that because I understand Velocity can be used in may different applications.
With a Confluence user macro, I check for a previously created attribute on the req variable, the request variable, i.e. "myPageVars". Then I use the put method to put a new key-value pair, based on the macro parameters. By using the $! prefix, rather than just $, the output isn't sent to the screen.
...
$!req.getAttribute("myPageVars").put( $paramKey, $paramValue )
...
I'm somewhat new to Velocity, so I can't guarantee this will work in every context, but it seems syntactically easier than the whole #set ($dummy etc. line.

Resources