Welcome Guest, Not a member yet? Register   Sign In
Grabbing and echoing only fragments of views
#11

[eluser]Dave Stewart[/eluser]
Excellent - I've done it, and made it pretty flexible as well!

You can now grab a fragment of any view in the usual CI way, with a method call such as:

Code:
$this->load->fragment($view, $vars, $pattern, $return);

Just like load->view() it parses any data sent to it, and can either be output straight to the page, or can be returned to be passed to any other view.

The main difference between load->view() is you now specify a pattern such as:

1 - A two-element array, consisting of a starting string and an ending string
2 - A regular expression
3 - A single tag name

Here's some example code:

Code:
.
// insert the div with an id of "users", using a regular expression
    $this->load->fragment('master', $vars, '%<(div) id="users"(.+)</$1>%', true);

// grab the HTML between 2 comments, using an array, then insert into a view
    $data['range'] = $this->load->fragment('master', $vars, array('&lt;!--start--&gt;', '&lt;!--end--&gt;'), true);
    $this->load->view('blog', $data);

Here's the code for the actual class:

Code:
&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_Loader extends CI_Loader{

    function MY_Loader()
    {    
        parent::CI_Loader();
    }
    

    // --------------------------------------------------------------------
    
    /**
     * Load Fragment
     *
     * This function is used to load a fragment of a "view" file.  It has four parameters:
     *
     * 1. The name of the "view" file to be included.
     * 2. An associative array of data to be extracted for use in the view.
     *
     * 3. A pattern to delimit the start and end of the fragment to be grabbed. It can be:
     *    1. A two-element array, consisting of a starting string, and an ending string
     *       The start and end string are included in the return value
     *    2. A regular expression
     *    3. A single tag name
     *
     * 4. TRUE/FALSE - whether to return the data or load it. In some cases it's advantageous
     *    to be able to return data so that a developer can process it in some way.
     *
     * @access    public
     * @param    string
     * @param    array
     * @param    array / string
     * @param    bool
     * @return    void
     */
    function fragment($view, $vars = array(), $pattern = '', $return = FALSE)
    {

        // ----------------------------------------------------------------------------------------------------
        // grab the view using the existing CI functions
            $output = $this->_ci_load(
                array(
                    '_ci_view' => $view,
                    '_ci_vars' => $this->_ci_object_to_array($vars),
                    '_ci_return' => TRUE
                    )
                );
                
        // ----------------------------------------------------------------------------------------------------
        // determine the delimiter type, and grab a fragment accordingly


            // regular expression
            // eg: "%<(body)(.+)</$1>%"
                if(is_string($pattern) && preg_match('/^(\W).+\1[imsxe]*$/', $pattern)){
                
                // make the pattern multiline and dot compatible
                    $pattern .= 'sm';
                    
                // do the match
                    preg_match($pattern, $output, $matches);
                    if(count($matches) >= 1)$output = $matches[0];
                    else trigger_error ("The fragment delineated by the regular expression <strong>'$pattern'</strong> was not found in the supplied view");
                    }
                    
            // single tag name
            // eg: "body"
                else if(is_string($pattern) && preg_match('%\[A-Za-z]+%', $pattern)){
                    $pattern = array("<$pattern", "</$pattern>");
                }

            // array - start delimter & end delimiter
            // eg: array('&lt;body', '&lt;/body>')
                if(is_array($pattern)){
                
                // start and end delimiter positions
                    $start            = strpos($output ,$pattern[0]);
                    $end            = strpos($output, $pattern[1]) + strlen($pattern[1]);
                    
                // check that delimiiters exist in output
                    if($start === false || $end === false){
                        trigger_error ("The delimiters <strong>'{$pattern[0]}'</strong> and/or <strong>'{$pattern[1]}'</strong> do not exist in the supplied view");
                        }
                    else{
                        $output = substr($output, $start, $end - $start);
                        }
                }
                
        // ----------------------------------------------------------------------------------------------------
        // output & return
            if($return == FALSE){
                echo $output;
            }
            return $output;
    }
    
}

And if you're using PHP4 you'll need to update the codeigniter/base4.php file, as detailed here: http://ellislab.com/forums/viewthread/83614/

Cheers,
Dave
#12

[eluser]stoefln[/eluser]
Exactly the thing i was searching for! Great you share this peace with us. I m currently developing an ajax application and cause i have to refresh just parts of the page its very usefull retrieving just parts of the template...
#13

[eluser]stoefln[/eluser]
retrieving the "taglist" div out of this view does not work for me.
Code:
$id = 'taglist';
$pattern = '%<(ul) id="'.$id.'"(.+)</$1>%';
return $this->fragment($view, $vars, $pattern, $return);
Code:
<div class="content-left">
    
    &lt;?=text2label($image->title)?&gt;
    &lt;?=$image->getHtmlTag(400,800)?&gt;
    &lt;?=text2label('Comments')?&gt;
</div>
<div class="content-right">
    [removed]
        
        document.observe("dom:loaded", function() {
            var ev = new EventManager();
            ev.init();
            
          });

    [removed]
    &lt;?=text2label('Details')?&gt;
    <dl>
    <dd>Created By</dd><dt>&lt;?= getUserButton($image->createdById,$image->createdByUsername)?&gt;</dt>
    <dd>Created On</dd><dt>&lt;?= formatDateTime($image->createdOn)?&gt;</dt>
    <dd>Tags&lt;?=getAddButton("addTagButton")?&gt;&lt;?=getSaveButton("saveTagButton","display: none;")?&gt;</dd>
    <dt>
        <ul id="taglist">
        &lt;? foreach(explode(' ',$image->tags) as $tag):?&gt;
            <li>&lt;?= getTagButton($tag).getDeleteButton("$('taglist').insert('<li>sdfg</li>');");?&gt;</li>
        &lt;? endforeach?&gt;
        </ul>
    </dt>
    <dd>Filename</dd><dt>&lt;?= $image->filename?&gt;</dt>
    <dd>Description</dd><dt>&lt;?= $image->description?&gt;</dt>
    </dl>
    <br/>

</div>
#14

[eluser]stoefln[/eluser]
i actually doubt that its as easy as in your code to retrieve a subpart by a elements id.
finally i got it running with following code:

Code:
/**
     * Load Fragment
     *
     * This function is used to load a fragment of a "view" file.  It has four parameters:
     *
     * 1. The name of the "view" file to be included.
     * 2. An associative array of data to be extracted for use in the view.
     *
     * 3. the id of the HTML element
     *
     * 4. TRUE/FALSE - whether to return the data or load it. In some cases it's advantageous
     *    to be able to return data so that a developer can process it in some way.
     *
     * @access    public
     * @param    string
     * @param    array
     * @param    string
     * @param    bool
     * @return    mixed
     */
    public function fragmentById($view, $vars, $elementId, $return = FALSE){
        
        $html = $this->_ci_load(
                array(
                    '_ci_view' => $view,
                    '_ci_vars' => $this->_ci_object_to_array($vars),
                    '_ci_return' => TRUE
                    )
                );
        $doc = new DOMDocument();
        $docHtml = '&lt;html&gt;'.$html.'&lt;/html&gt;';
        $doc->loadXML($docHtml);
        // we need a schema here since php needs a validation step befor the method "getElementById"
        $rng = '<grammar >
            <start>
                <element>
                    <anyName/>
                    <ref name="anythingID"/>
                </element>
            </start>
            <define name="anythingID">
                <zeroOrMore>
                    <choice>
                        <element>
                            <anyName/>
                            <ref name="anythingID"/>
                        </element>
                        <attribute name="id">
                            <data type="ID"/>
                        </attribute>
                        <zeroOrMore>
                            <attribute><anyName/></attribute>
                        </zeroOrMore>
                        <text/>
                    </choice>
                </zeroOrMore>
            </define>
        </grammar>';
        $doc->relaxNGValidateSource($rng);
        $element = $doc->getElementById($elementId);
        if(!$element){
            throw new Exception("No element with id \"".$elementId."\" found!");
        }
        $subpart = '';
        // loop through all childNodes, getting html
        $children = $element->childNodes;
        foreach ($children as $child) {
            $tmp_doc = new DOMDocument();
            $tmp_doc->appendChild($tmp_doc->importNode($child,true));
            $subpart .= $tmp_doc->saveHTML();
        }
        if($return == FALSE){
            echo $subpart;
        }
        unset($tmp_doc);
        unset($doc);
        return $subpart;
    }




Theme © iAndrew 2016 - Forum software by © MyBB