Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID

How to replace parts of a page dynamically

edited August 2013 in Design

Clicking on one of the thumbnails on the right should populate the left side with the appropriate larger image, description, etc.

Mockup

I made a simple crud app that lets them add/edit titles, price, etc., which will show on the left of the page when the corresponding thumbnail is clicked. Would it make sense to use jQuery.load() to replace the left section on click?

Comments

  • That seems like a pretty reasonable approach to me.

    The other option, which is probably a little more complicated, would be to save out all the data for all the albums to Javascript like this:

    <script>var albums = {{album_list|json_encode}};</script>
    

    This assumes the template was passed album_list as an array of objects. Then have the click event replace the left column with a client-side rendered template (using something like handlebars).

    The trade-off is between fetching each album separately (with probably faster initial page load, but separate server calls for each album click) versus loading all at once and then everything being client-side (with more data fetched initially, plus the extra client-side template logic, but faster responses once it's rendered).

    I'd probably just go the jQuery.load() route :)

  • Thanks. Should the layout that I use have < html > and < head > sections, or should it just include the (say) < div > that contains the data?

  • Probably just the div I would think.

  • edited August 2013

    If you already have a page that contains the part you need, maybe you could load the page fragment.

    For example:

    $('#target').load('thepage.html #fragment');
    
  • That's a good idea, but I already have it working loading mini-layouts. I'll post a link when it goes live.

  • edited August 2013

    For logged in admins, I want to show the elefant edit/add/versions/delete buttons in the left pane (the parts that gets replace onclick). That's no problem in the divs that load via jquery, but I'm stumped about how to show the ones specific to the initial CD when the page first loads. Obviously I need to add the show button code to the handler, but how do I get the buttons to show up inside the left pane so that they're replaced when a different CD is loaded?

    I guess what I'm asking is how do I call the buttons from the view.

    Index handler:

    <?php
    
    $page->add_style ('/css/cds.css');                           
    $query = cds\CD::query ();                                   
    $query->order ('rank');                                      
    $feature = $query->fetch (1);                                
    $feature = $feature[0]->orig();                              
    $query = cds\CD::query ();                                   
    $query->where ('on_hold = 0');                               
    $query->order ('rank');                                      
    $items = $query->fetch ();                                   
    // info (DB::$last_sql);                                     
    
    echo $tpl->render ('cds/index',                              
        array (                                                  
            'items' => $items,                                   
            'feature' => $feature                                
        )                                                        
    );                                                           
    
    ?>
    

    Index view:

    <div id="cds">
        <div id="cds-left-pane">
            <p>The latest release from Barnes &amp; Hampton</p>
            <p class="cd-centered"><img src="{{ feature->image }}" alt="{{ feature->name }}"><br>{{ feature->publisher }}</p>
            <p>{{ feature->description|none }}</p>
            {% if feature->sample|file_exists %}
            <p class="cd-centered"><a href="{{ feature->sample }}">Listen to {{ feature->name }}</a></p>
            {% endif %}
            <p class="shipping">${{ feature->price|number_format }}, U.S Shipping, add ${{ feature->us_shipping|number_format }}</p>
            <div>{{ feature->paypal_us|none }}</div>
            <p class="shipping">${{ feature->price|number_format }}, Foreign Shipping, add ${{ feature->foreign_shipping|number_format }}</p>
            <div>{{ feature->paypal_foreign|none }}</div>
        </div>
        <div id="cds-right-pane">
        {% foreach items %}
            <p class="cd-thumbnail"><a href="/cds/cd/{{ loop_value->id }}" onclick="$('#cds-left-pane').load('/cds/left-pane/{{ loop_value->id }}'); return false;"><img src="{{ loop_value->image }}" alt="{{ loop_value->name }}"></a></p>
        {% end %}
        </div>
    </div>
    

    Left pane handler:

    <?php
    
    list ($id) = $tpl->controller->params;
    $page->layout = 'cds';
    
    $query = cds\CD::query ();
    $query->where ('id', $id);
    $feature = $query->fetch ();
    $feature = $feature[0]->orig();
    
    // show admin edit buttons
    if (User::is_valid () && User::is ('admin')) {
        $lock = new Lock ('CDs', $id);
        $feature->locked = $lock->exists ();
        echo $tpl->render ('cds/editable', $feature);
    }
    
    echo $tpl->render ('cds/left-pane',
        array (
            'feature' => $feature
        )
    );
    
    ?>
    

    Left pane view:

    {% if feature->rank == 1 %}<p>The latest release from Barnes &amp; Hampton</p>{% endif %}
            <p class="cd-centered"><img src="{{ feature->image }}" alt="{{ feature->name }}"><br>{{ feature->publisher }}</p>
            <p>{{ feature->description|none }}</p>
            {% if feature->sample|file_exists %}
            <p class="cd-centered"><a href="{{ feature->sample }}">Listen to {{ feature->name }}</a></p>
            {% endif %}
            <p class="shipping">${{ feature->price|number_format }}, U.S Shipping, add ${{ feature->us_shipping|number_format }}</p>
            <div>{{ feature->paypal_us|none }}</div>
            <p class="shipping">${{ feature->price|number_format }}, Foreign Shipping, add ${{ feature->foreign_shipping|number_format }}</p>
            <div>{{ feature->paypal_foreign|none }}</div>
    

    It's called as a dynamic element from a page.

    Initial load (missing CD-specific add/edit/etc. buttons): Initial load

    After clicking one of the right-hand images (has both sets of buttons -- page and CD): After click

  • I would render the buttons inside the view template like this:

    {! cds/editable?feature=[feature] !}
    

    Then move the code for it to a new handler (apps/cds/handlers/editable.php):

    <?php
    
    if (isset ($data['feature']) && is_object ($data['feature'])) {
        $feature = $data['feature'];
    } else {
        return;
    }
    
    // show admin edit buttons
    if (User::require_acl ('admin')) {
        $lock = new Lock ('CDs', $feature->id);
        $feature->locked = $lock->exists ();
        echo $tpl->render ('cds/editable', $feature);
    }
    
    ?>
    

    That should be able to replace the equivalent code in both places, and let you put the edit buttons exactly where you want them in your views.

  • Thanks. It seems like it should work, but I'm getting an error when I put {! cds/editable?feature=[feature] !} in a view:

    ErrorException: htmlspecialchars() expects parameter 1 to be string, object given
    
    htmlspecialchars (stdClass, 11, "UTF-8")
    585 /path/to/lib/Template.php
    
    583.             define ('ENT_SUBSTITUTE', ENT_IGNORE);
    584.         }
    585.         return htmlspecialchars ($val, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
    586.     }
    587.
    
    Template::sanitize (stdClass, "UTF-8")
    3 /path/to/cache/cds-index.php
    
    1. <div id="cds">
    2.     <div id="cds-left-pane">
    3.         <?php echo $this->controller->run ('cds/editable', array ('feature' => Template::sanitize ($data->feature, 'UTF-8'))); ?>
    4.         <p>The latest release from Barnes &amp; Hampton</p>
    5.         <p class="cd-centered"><img src="<?php echo Template::sanitize ($data->feature->image, 'UTF-8'); ?>" alt="<?php echo Template::sanitize ($data->feature->name, 'UTF-8'); ?>"><br><?php echo Template::sanitize ($data->feature->publisher, 'UTF-8'); ?></p>
    

    However, if I change [feature] to [feature->id] and then change the top of the handler to...

    $feature = new cds\CD ($data['feature']);
    
    if (!is_object ($feature)) {
        return;
    }
    

    ...it works fine. Kosher?

  • I think this should fix it:

    {! cds/editable?feature=[feature|none] !}
    

    The htmlspecialchars() filter doesn't need to be called. This way also avoids an extra database call in the cds/editable handler.

    Let me know how that works!

  • Works like a charm. Thanks!

  • Nice! The discography browsing works really well!

Sign In or Register to comment.