Jump to content

ajax-enabled inputfield - options?


Rob
 Share

Recommended Posts

I've built a custom InputField module that consists of 2 combo boxes. When the value in the first is selected, it pings an ajax request to the server to fetch values for the second combo box. At present I have had to create a new page with the processing code in the template (and nothing else) to handle this request. It's not very self-contained (InputField and Fieldtype files including JS, plus totally separate request handling page created by hand) so I wondered if I can have a method in my InputField/Fieldtype code to handle the request if I post that request to the same page it is part of?

i.e. post it to itself (the current page).

Thanks in advance.

Link to comment
Share on other sites

I don't think so. Creating a separate process module is the only way as far as I know, and perfectly valid to do so.

I was looking into this, and that's what had occurred to me. What I can't figure out is how to attach a process module to a page. On the pages underneath admin, there has been a "process" field attached to the template, but I don't have that field available on regular page templates.

Am I missing something? (I know the answer is yes!)

Link to comment
Share on other sites

You'd have to create a admin page somewhere in /admin/ that uses the process module as process. Then you can ping the url.

That's essentially what I'm already doing, and I think it's a bit messy, but I accept it's a slightly messy thing I'm trying to achieve!

If I wanted to make the process a one-click install in a self-contained module, could I install the Fieldtype/Inputfield modules, the process module, create the admin page and attach the process module to that page all from a module code? I believe that modules can express dependencies on other modules, but can modules automatically install other modules?

Thanks for the help!

Link to comment
Share on other sites

I don't quite understand what is messy about it? Well, I don't know if it would be possible to hook the admin edit page process on execute method and do something, but I think you want to avoid doing it anyway and have a dedicated process for your fieldtype.

However you can create something on install of the module. Have the Inputfield install the process module and on that process module you have something like:

public function ___install() {
 $p = new Page();
 $p->template = $this->templates->get("admin");
 $p->parent = $this->pages->get(3); // /processwire/page/
 $p->title = 'MyProcess';
 $p->name = 'myprocess';
 $p->process = $this;
 $p->save();
}

Edit: For module dependencies there's a thread dedicated to that http://processwire.c...e +dependencies

Link to comment
Share on other sites

Ah OK that makes sense in terms of assigning the process of a page to the module, but how do I get the module to install the process module? Or indeed get an InputField to install a FieldType, or vice versa?

I guess it makes sense to create a page to handle the request, but I'd just like the process of installing all these related modules be a single step, rather than having to manually install multiple modules, and that's the bit I can't work out how to do.

Link to comment
Share on other sites

Another way to install a module is to use API call

$modules->get("modulename");
//or
wire("modules")->get("modulename");

Any module called like this not yet installed will get installed.

Link to comment
Share on other sites

You don't necessarily need to create a separate Process module if you don't want to. Though there's nothing wrong with doing it that way, and it may make sense for a separation of powers deal. If you take that approach, your render() function can simply return the content to be output and ProcessWire will take care of the output for you (it outputs only your returned output, without any template output, when the request is ajax). But there are other ways of handling it within your existing module.

1. If you are retrieving pages, ProcessWire already has an Ajax-API built in for you to use. This is what the Autocomplete inputfield uses, for example. It'll let you query and retrieve just about anything that you could from a native PW API call. See here for more info. This at least answers 90% of the AJAX needs I have in ProcessWire.

2. If either your Fieldtype or Inputfield is autoload, you can have it listen for your ajax request in the module's init():

public function init() {
 // look for ajax request and some variable you've set as your landmark to look for
 if($this->config->ajax && $this->input->post->rob == 'rob' && !$this->user->isGuest()) { 
   // do your thing, outputting your JSON/XML or whatever
   exit(); 
 }
}

In the above scenario, you could ping literally any page and so long as the request came from ajax and $_POST['rob'] == 'rob', your bit of code would get executed.

You might also be able to get away with doing this in your $inputfield->init() (non-autoload) function, which would prevent you from having to check for access, and would ensure the execution is limited to when your module comes into play. However, I haven't tried that to confirm.

Link to comment
Share on other sites

Ryan - is it possible to create a page that has a Process attached but that also has fields as a normal page might?

The context is that I want a page that has a couple of fields for storing data, but also a process attached so I can ping ajax requests and process them.

I'm having trouble understanding if what I want to do is possible. It runs something like:

1. Create a module that install a bunch of other modules (fieldtype, inputfield, process), I know how to do this with "install" and "require" parts of module info.

2. Create a template (in module code)

3. Add a couple of fields to this template (in module code)

4. Create a page based on this template (in module code)

5. Attach process module to handle ajax requests (in module code)

6. save the page into the page tree (in module code)

The idea behind all this is a one-click install of a system that creates a page that acts as an image repository (just a massive bunch of images with some extra metadata stored, tags etc), and install my custom field I have created that allows ajax filtering of the images stored on the repository page.

I was hoping to develop this idea for the benefit of the community but I feel like it's no good if it involves many steps and lots of manual work!

I am sure this must be possible one way or another, and I am determined to get it working. Soma has been a great help so far!

Link to comment
Share on other sites

Ryan - is it possible to create a page that has a Process attached but that also has fields as a normal page might?

This is certainly possible. Unless I'm overlooking something, you should be able to do this now by adding the 'process' field to your template. If you prefer, you can always create your own field like 'process', which is just a field of FieldtypeModule. But might as well just use the one that's already there unless you have a need to make it different. The 'process' field is considered a system field, so the admin UI may not let you add it to a template unless you have $config->advanced=true; in your /site/config.php. However, if you are doing this from the API, it shouldn't matter.

ProcessWire 'admin' executes the Process modules by including /wire/core/admin.php. You could setup your own template to do the same thing, by including that file. Though you can also have your template execute the Process on your own too. Here's how you do it:

$controller = new ProcessController();
$controller->setProcessName($page->process); 
$output = $controller->execute(); 
Link to comment
Share on other sites

Ryan - thanks for the pointers.

The problem I'm having, however, is that I don't actually have a template php file, I'm creating a template, fieldset and fields and tying it all together within my module install() code. This all works fine so far, so I have a one-click module that installs some custom Inputfield modules, creates a template and then creates a page from that template.

At this point I have a page under /processwire/pages/imagerepo that has a single images field that can be uploaded to etc.

What I also want is for that page to be able to receive and process an ajax request. I added an executeXYZ() method but it is never being called because I can't work out how to trigger the ProcessController. I can't "attach" code to the (non-existent) template from within my module install method, so at present it seems like my only option is to create a second page that is of type admin and attach a process to that.

This is no problem as such, it just seems to me that it would be cleaner to have a single page that handles all this as opposed to one page to hold the images and another to actually handle requests.

This is all great module development practise so I'm not complaining!!

Link to comment
Share on other sites

I think you can do this with just having a single page. When your module creates your template, assign this property to it before saving it:

$template->altFilename = 'admin.php';

That will make your template use the existing admin template when it comes time to render the page, hopefully executing your process along with it.

If you want to test it out before going in the code, this is also a property you can set from PW's template settings. Edit the template and then click on the 'advanced' tab. You'll see a setting there called 'Alternate Template Filename'.

Link to comment
Share on other sites

Great, I'll try it, thanks!

One more quick one while I know you're here!!

I'm having trouble returning json data from an executeXYZ() fucntion in my process module. I originally had an ajax.php template handling the request but as mentioned in previous post, I have now tried having a code-created admin page with process attached to handle the request.

Should I just be returning the json data from the executeXZY() method in my process module code? I use the following code to create page and attach the process to the page:

$page = new Page();
 $page->parent = $parent;
 $page->template = wire('templates')->get('admin');
 $page->name = "imagerepo-handler";
 $page->title = "Image Repo Request Handler";
 $page->process = $this;
 $page->save();

I then have the following method to try to handle an ajax request and return some json:

public function executeFetch() {
 switch($input->get->action) {
  case "fetchimages":
$tags = $input->get->tags;
$grabimages = wire('pages')->get('/processwire/page/imagerepo-handler/')->imagerepo->find("tags%=$tags");
break;
 }
 $data = array();
 foreach($grabimages as $item) {
  $image = $item->data;
  $image['url'] = $item->url();
  $data[] = $image;
 }
 return json_encode($data);
}

Any obvious problems with this code?

Link to comment
Share on other sites

Your executeFetch method will only get called if the URL is /path/to/your/page/fetch. Since Process modules make use of URL segments, make sure your template has urlSegments enabled. I think what your executeFetch method is doing looks fine from the aspect of it returning JSON. Note that PW is going to output that JSON in the middle of an admin template unless the request actually comes in through ajax. So if you see JSON in the middle of PW's admin template, don't worry, just try it again pulling the data from ajax and PW should detect that and only output your JSON.

Link to comment
Share on other sites

Thanks for all the help, my module is coming along nicely.

The process of creating fields, templates and pages all on-the-fly makes me wonder if it's a good technique for creating blog-in-a-box type functionality. That is to say, being able to install a single module and have certain types of fields and pages immediately generated seems like a nice idea for beginners and less experienced users who are a bit intimidated by the "roll-your-own-schema" nature of Processwire.

I understand that "site profiles" offer some of this, but to be able to one-click installation modules for common functionality that requires template types and custom fields might be easier than entire site installs or how-to tutorials that explain the manual steps.

I might break this out into a separate thread for if it's worth discussion.

Link to comment
Share on other sites

I agree that type of functionality is very useful. I think that Nico's blog module basically did this. But there is no doubt a lot of untapped potential here, and possibly dedicated tools to use for the import/export of this stuff.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...