Skip to content
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

Get Array Length #43

Closed
gyscos opened this issue Oct 9, 2015 · 9 comments
Closed

Get Array Length #43

gyscos opened this issue Oct 9, 2015 · 9 comments

Comments

@gyscos
Copy link

gyscos commented Oct 9, 2015

Handlebars support accessing an array length:

List length: {{my_list.length}}
{{#each my_list}}...{{/each}}

(For instance see http://stackoverflow.com/questions/15428584/how-to-find-array-length-inside-the-handlebar-templates)

It seems this is currently not supported in handlebars-rust.

The workaround I used was to add a length custom helper (candidate for built-in helpers?), but maybe following the original syntax would also be a good idea?

@gyscos gyscos changed the title Array length of current pipeline Get Array Length Oct 9, 2015
@gyscos
Copy link
Author

gyscos commented Oct 9, 2015

Considering context::navigate returns a &Json, it'll be hard to have it return the length. I guess changing the function to return a Cow would be a solution, but I'm not sure it's super convenient...

@sunng87
Copy link
Owner

sunng87 commented Oct 10, 2015

In rust we only have a JavaScript type system, but no expression support built-in. Currently you can use a helper like this (not tested, need error check):

// implement via bare function
fn alength_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    let param = h.params().get(0).unwrap();
    let value = c.navigate(rc.get_path(), param);
    try!(rc.writer.write(value.as_array().unwrap().len().to_string().into_bytes().as_ref()));
    Ok(())
}

Supporting these special properties like length in context.navigate is also a good idea. But we may need to implement all javascript native properties. Currently I have no idea about how much work it needs.

@csirkeee
Copy link

It's still true that length doesn't work in Rust Handlebars, and works in the original JS Handlebars. The helper that was posted here by @sunng87 only worked with earlier versions of the library. Since then, the helper method signature changed, and Handlebars switched to Serde, so I had to make some modifications.

Here is a version of the helper that works with current Rust/Handlebars/Serde, in case someone else also finds this issue on GitHub, and this can be useful to them. This version follows what seems to otherwise be Handlebars standard of outputting nothing if the input didn't make sense, and not panicing.

use rocket_contrib::handlebars::{Handlebars, Helper, RenderContext, RenderError};
use serde_json::value::Value;

type HelperResult = Result<(), RenderError>;

pub fn length_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> HelperResult {
    if let Some(param) = h.param(0) {
        let param = param.value();

        if let &Value::Array(ref array) = param {
            rc.writer
                .write(array.len().to_string().into_bytes().as_ref())?;
        }
    }

    Ok(())
}

@novakov-alexey-zz
Copy link

novakov-alexey-zz commented Oct 4, 2018

@csirkeee is RenderContext from rocket_contrib crate?
if I use RenderContext directly from extern crate handlebars, I am missing writer field in it. I am wondering if this struct is evolved since then. However, there is handlebars module at rocker_contrib version=0.3.16

6 | use self::rocket_contrib::handlebars::{Handlebars, Helper, RenderContext, RenderError};
  |                           ^^^^^^^^^^ Could not find `handlebars` in `rocket_contrib`

@sunng87
Copy link
Owner

sunng87 commented Oct 5, 2018

@nnovakov-alexey it says handlebars not available from rocket_contrib, did you have handlebars feature turned on when importing rocket_contrib?

@novakov-alexey-zz
Copy link

@sunng87 yes, exactly.

extern crate rocket_contrib;
use rocket_contrib::handlebars::{Handlebars, Helper, RenderContext, RenderError};

rocket_contrib = {version="0.3.16", features = ["handlebars_templates"]}
I am also using hanlebars explicitly for my project in toml file:
handlebars = "1.0.4"

@sunng87
Copy link
Owner

sunng87 commented Oct 5, 2018

@novakov-alexey as of 1.0, there is no writer in RenderContext any more. Use the Output to write bytes.

Rocket contrib 0.3.16 was using handlebars 0.x version, and it will conflict with 1.0. I suggest you to use git version, or remote explicit handlebars = 1.0.4 to see if it would work.

@novakov-alexey-zz
Copy link

@sunng87 thanks for advice. Yes, I am using remote explicit handlebars = 1.0.4.
Actually, I am trying to make @csirkeee example above working with standalone handlebars. @sunng87 which Output do you mean please? :-) I am quite new to Rust ecosystem.

@novakov-alexey-zz
Copy link

novakov-alexey-zz commented Oct 5, 2018

Answering my question as for helper to get array length using standalone handlebars crate:

extern crate handlebars;
use handlebars::*;

pub fn array_length_helper(
    h: &Helper,
    _: &Handlebars,
    _: &Context,
    _: &mut RenderContext,
    out: &mut Output,
) -> Result<(), RenderError> {
    let length = h
        .param(0)
        .as_ref()
        .and_then(|v| v.value().as_array())
        .map(|arr| arr.len())
        .ok_or(RenderError::new(
            "Param 0 with 'array' type is required for array_length helper",
        ))?;

    out.write(length.to_string().as_ref())?;

    Ok(())
}

Cargo.toml
handlebars = "1.0.4"

Usage:

{{#each fields as |field| ~}}
        <tr>
          {{#if (lt @index 1)}}
            <td valign="top" class="td3" rowspan="{{array_length ../fields}}">
.....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants