Returning page attributes with AJAX

Permalink
Full disclosure before I start; never touched AJAX before, just sort of stumbled through it this weekend as it seems the only way to work some functionality I need, so may be doing this very wrong, and what I'm ultimately trying might not even be possible.

First off, in my .js I have the following, which is taking a preset value from a selected checkbox (the value being a page ID) and sending it to my ajax php script;
$(document).ready(function() {
  $('.product-filter').change(function(){
    $.ajax({
      url: 'filter-ajax.php?filter='+$(this).val(),
      success: function(data){
        $('#filterResponse').html(data);
      }
    });
  });
});


I've checked that this is working by just echoing back the value from the .php file to the page like so;
<?php
    $filter = $_GET['filter'];
    echo '<p>'.$filter.'</p>';  
?>

And it does the job, the page ID set from the selected checkbox gets printed to the page.

But what I need is for that page ID to be worked through some more php and have that parsed code returned, as in;
<?php
    $filter = $_GET['filter'];
    $d = PAGE::getByID($filter);                
    $page = $d->getCollectionName();
    echo '<p>'.$page.'</p>';
    $attr_set = AttributeSet::getByHandle('technical');
    $attr_keys = $attr_set->getAttributeKeys();
    foreach($attr_keys as $ak) {
        echo '<p>'.$ak->akName.'</p>';
        echo '<p>'.$d->getAttribute($ak->akHandle).'</p>';
    };
?>


So basically, when the checkbox is selected, I need this to send back to the body of the page the page name for the selected option, and the page attributes for that page (the code there for those is working fine, I just need to be able to switch which page it pulls them from dynamically).

I'm also pretty sure I'm doing something more fundamentally wrong, as
<?php
    $filter = $_GET['filter'];    
    $d = PAGE::getByID($filter);                
    $page = $d->getCollectionName();
    echo '<p>'.$page.'</p>';
?>

doesn't work either, so I think nothing there's getting parsed?

Been googling and searching through tutorials and FAQs for a good few hours now, and not any closer to making this work. I've seen JSON mentioned a few places, but it doesn't seem like it'll do what I need, and I'm just about getting my head around this part at the moment as it is.

 
hutman replied on at Permalink Reply
hutman
Does it work if you change PAGE to Page?
ErikM replied on at Permalink Reply
Hello again.

Nope, and I'd have been really surprised if it did, as the code works when put directly into the page with a page id put in by hand.
The problem is getting it parsed and sent back. I'm 98% sure, anyway.
mnakalay replied on at Permalink Reply
mnakalay
Hello,
you are echoing your result in your PHP file but that file is not attached to your page in any way, it is just an external tool called by ajax.

From that php file you need to send the result back to ajax that will then show it on the page throughout normal jquery dom manipulation.

from your PHP, you could put your return values (page name...) in an array
$ret = array('name' => $d->getCollectionName);

then after your array is ready you do
$json = Core::make('helper/json');
echo $json->encode( $ret);
exit;

We are encoding the array to json for ajax to consume.

Now you need to alter your original ajax call to use that return data
$.ajax({
   url: 'filter-ajax.php?filter='+$(this).val(),
   dataType: "json"
}).done(function(data, textStatus, jqXHR){
   var name = data.name;
   $('#filterResponse').html(name);
}).fail(function(jqXHR, textStatus, errorThrown){
   if (textStatus === 'parsererror') {
      alert('Requested JSON parse failed.');
   } else if (textStatus === 'timeout') {
      alert('Time out error.');
   } else if (textStatus === 'abort') {
      alert('Ajax request aborted.');
   } else if (jqXHR.status === 0) {
      alert('Not connected.\n Verify Network.');


Notice I am using .done() instead of success which is deprecated
ErikM replied on at Permalink Reply
Thanks for your help.

My php file is now;
<?php
    $filter = $_GET['filter'];
    $d = page::getByID($filter);                
    $ret = array('name' => $d->getCollectionName);
    $json = Core::make('helper/json');
    echo $json->encode( $ret);
    exit;
?>


and my .js is;
$(document).ready(function(){
  $('.product-filter').change(function(){
   $.ajax({
      url: 'filter-ajax.php?filter='+$(this).val(),
      dataType: "json"
   }).done(function(data, textStatus, jqXHR){
      var name = data.name;
      $('#filterResponse').html(name);
   }).fail(function(jqXHR, textStatus, errorThrown){
      if (textStatus === 'parsererror') {
      alert('Requested JSON parse failed.');
      } else if (textStatus === 'timeout') {
         alert('Time out error.');
      } else if (textStatus === 'abort') {
         alert('Ajax request aborted.');


And this is returning the Internal Server Error [500].
mnakalay replied on at Permalink Reply
mnakalay
usually that means a PHP error. Try correcting your code to have
$d = Page::getByID($filter);

notice the capital P in Page.

In what context are you using this code? In a theme's page type? In a block?
ErikM replied on at Permalink Reply
Still the Internal Server Error

I'm currently trying to work it into the a page template in the theme. It seemed the simplest way to see if I could get it working without throwing a lot of other potential problems into the mix.

If it's relevant, filter-ajax.php is in the site's root as it wouldn't seem to work anywhere else.
JohntheFish replied on at Permalink Reply
JohntheFish
Have you registered the ajax route?
ErikM replied on at Permalink Reply
Nope, going to have to profess ignorance there.
How might that look for a call from the page template rather than a block?
JohntheFish replied on at Permalink Reply
JohntheFish
You would set it up in a controller on_start event handler. Either using controllers for your theme pages, or the package controller.
jasteele12 replied on at Permalink Reply
jasteele12
For testing purposes you can just add some MVC routes in application/bootstrap/app.php

I like the legacy tools since all I have to do is upload a single file and call it ;)

You can name your routes however you want, but this (untested) example would make your new AJAX url: '/task/' + $(this).val()
// return a JSON encoded pageID name (route parameter id)
Route::register('/task/{id}', function($id) {
  $id = intval($id);
  if ($id < 1) {
    $ret = array('error' => 'Invalid Page ID');
  } else {
    $d = Page::getByID($id);
    if (is_object($d)) {
      $ret = array('name' => $d->getCollectionName);
    } else {
      $ret = array('error' => 'Failed to retrieve page');
    }
  }
  $json = Core::make('helper/json');
  echo $json->encode($ret);

Here's how to fake some tools:
// fake legacy tools file functionality
Route::register('/tools/{name}', function($name) {
  $name = trim($name);
  if ($name) {
    $file = 'application/tools/'. $name. '.php';
    if (is_readable($file)) {
      include $file;
    }
  }
});
  // or, just a single one
Route::register('/tools/get-vars', function { include 'application/tools/get-vars.php'; });