renderInTemplate() forgives to escape # for nested template

5 posts, 1 answers
  1. Paolo
    Paolo avatar
    27 posts
    Member since:
    Mar 2017

    Posted 19 Dec 2017 Link to this post

    HI

    I am using renderInTemplate() to nest some widget, in particular, grid inside a window, I discovered the following method is missing to replace # in case the widget is nested inside another and the inner one contains in its definition a template string, so I suggest to patch width in a similar way ( more testing by your side is needed but It permitted to remova a Uncaught Error: Invalid template:' error in my application )

     

         public function renderInTemplate() {
            $this->isClientTemplate = true;
            $output = $this->render();
            $this->isClientTemplate = false;
            $output = str_replace('</script>', '<\\/script>', $output);

            // ADD THIS LINE to Replace also hash to prevent Uncaught Error: Invalid template:'

            return str_replace('#', '\\#', $output);
        }

     

     

  2. Dimitar
    Admin
    Dimitar avatar
    380 posts

    Posted 21 Dec 2017 Link to this post

    Hello Paolo,

    Thank you for the feedback provided.

    In order to properly handle the # character in a binding expression of a nested template, this character must be escaped with via \\# and this behavior is implemented by design. In this way the character is ignored by the outer template, but is handled correctly by the inner template. This is documented in the official Templates Documentation:


    Regards,
    Dimitar
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.


  3. Paolo
    Paolo avatar
    27 posts
    Member since:
    Mar 2017

    Posted 20 Mar in reply to Dimitar Link to this post

    Hi Dimitar, I will try to explain better the problem that I think many others developer could have :

    1. We need to call $grid->renderInTemplate() for a grid that in turn contains some columns with a custom column template
    2. the output from renderInTemplate() must be placed in a script text/x-kendo-template for later use ( es: as content in a kendoWindow )
    3. the stock renderInTemplate() function on Widget php class, only escape the jquery id selector with backslash but it doesn't escape the #s different by the jquery widget id, for example
      1. #s present in a custom template column
      2. #s present in an event handler for a widget set via Widget.prototype.bind() 
    4. In our scenario we render the text/x-kendo-template via kendo.template() , so # left unescaped cause invalid template exception
    5. Your code is useful in scenario like Nested Kendo Grid https://demos.telerik.com/kendo-ui/grid/hierarchy , where you need # left unescape
    6. If you need a complex scenario where some # must be left unescaped a mixed approach should be adopted

    Conclusion : it could be useful have another function like the following:

    trait HasTemplateRendering
    {
        public function renderInTemplateEx($placeholders=[])
        {
            /**
             * + Replace every # not yet escaped
             * + Doesn't replace # preceded or followed by { and } , es: {# or #} are not escaped

             *   and they will be left unescaped

             * + makes a search/replace of placeholders specified in the associative arrays placeholders

             *   at server runtime.

             */
            return self::renderInTemplateImpl($this,$placeholders);
        }
     
        public static function renderInTemplateImpl(Widget $widget,$placeholders=[])
        {      
            $output = $widget->renderInTemplate();
            $output = preg_replace('/(?<!({|\\\\))#(?!})/', '\\#', $output);
            /**
             * Search :placeholders and replace them with their values
             */
            $output = preg_replace_callback('/:([[:alpha:]_][[:alnum:]_]*)/',function($match)use($placeholders){
                return isset($placeholders[$key = $match[1]]) ? $placeholders[$key] : $match[0];
            },$output);
            /**
             * Replace '{#','#}' with #
             */
            return preg_replace(['/({#)|(#})/'],'#',$output);
        }
    }

     

  4. Answer
    Dimitar
    Admin
    Dimitar avatar
    380 posts

    Posted 20 Mar Link to this post

    Hello Paolo,

    Thank you for sharing your solution with the community. 

    I will review it and create a Knowledge Base Article based on the provided extension, so that approach is also available in the official documentation. 

    Regards,
    Dimitar
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  5. Paolo
    Paolo avatar
    27 posts
    Member since:
    Mar 2017

    Posted 23 Apr in reply to Dimitar Link to this post

    Nice ! thanks
Back to Top