Content from a page in a panel dropdown

Hi Kirby pros,
I came up with an idea for an easy-to-use solution for my project.
Scenario
I have a unpublished page with a collection of addresses and these addresses can be changed or new items added comfortable via Panel. On Panel for the public page the editor have a drop-down field with e.g. the name and then I can print out the address on the page.
Question
Is it possible to show (part of) content from a page into the panel from another page?

Info
Without hundreds of lines of code ’cause I’m a frond-end guy without real PHP skills. Unfortunately.

Best,
Andreas

its a Rly Good and Helpfull Idea :slight_smile:

This is no problem. The solution depends on your setup. How do you want to add the collection of addresses? As children of “addresses” or as a structure field?

If you use a structure field, you would need a custom field to query the items from it into your select. If you use child pages, you don’t.

No problem? Wow!

I’ve set up a structured field and I already have an ”special field“. But I’ve no idea for a scripted/dynamic connection between the list and the select. My stupid and un-dynamic solution is at the moment to put the surname into the ”special field“ and the exact same list of surnames for the select. Not ideal.

Pages doesn’t make sense 'cause of the type of content. 30 – 40 addresses are much more easily to maintain as a compact list.

If you post your blueprint, it would be easier to help with the code:wink:

1 Like

Of course:

title: Page
pages: false
files: false
deletable: false
fields:
  addresses:
    label: Adressen
    type: structure
    entry: >
      {{addr_salutation}} <b>{{addr_title}} {{addr_name}}</b> &middot; {{addr_street}} &middot; {{addr_zip}} {{addr_city}}<br />
      Telefon: {{addr_tel}}
    fields:
      addr_salutation:
        label: Anrede
        type: select
        options:
          Mann: Mann
          Frau: Frau
        width: 1/2
        required: true
      addr_title:
        label: Titel
        type: select
        options:
          Dr.: Dr.
          Prof.: Prof.
        width: 1/2
      addr_name:
        label: Vorname + Nachname
        type: text
        required: true
      addr_street:
        label: Straße + Hausnummer
        type: text
        required: true
      addr_zip:
        label: PLZ
        type: text
        required: true
        width: 1/2
      addr_city:
        label: Ort
        type: text
        required: true
        width: 1/2
      addr_tel:
        label: Telefonnummer (Vorwahl-Nummer)
        type: tel
        required: true
```
and from the other blueprint the select:

treat_doctor:
label: Behandelder Arzt
type: select
options:
Arzt 1: Arzt 1
Arzt 2: Arzt 2
Arzt 3: Arzt 3
Arzt 4: Arzt 4
Arzt 5: Arzt 5

Ok, a custom field that fetches the entries from the structure field could look like this (this is just a simple copy of the select field with a modification that fetches the entries from a page called “addresses”, you would have to adapt this to your page name):

<?php

class AddressesField extends BaseField {

  public function __construct() {
    $this->type    = 'addresses';
    $this->icon    = 'chevron-down';
    $this->label   = 'category';
    $this->options = array();

  }  
public function options() {
    return FieldOptions::build($this);
  }
  public function option($value, $text, $selected = false) {
    return new Brick('option', $this->i18n($text), array(
      'value'    => $value,
      'selected' => $selected
    ));
  }
    public function input() {
      $select = new Brick('select');
      $select->addClass('selectbox');
      $select->attr(array(
        'name'         => $this->name(),
        'id'           => $this->id(),
        'required'     => $this->required(),
        'autocomplete' => $this->autocomplete(),
        'autofocus'    => $this->autofocus(),
        'readonly'     => $this->readonly(),
        'disabled'     => $this->disabled(),
      ));
        
    $select = $select->append($this->option('', '', $this->value() == ''));

    
    
    if($this->readonly()) {
      $select->attr('tabindex', '-1');
    }

    if(page('addresses')->addresses()) {
      $addresses = page('addresses')->addresses()->toStructure();
    }
   
    foreach($addresses as $address)  {
      $name = $address->addr_name();
      $this->options[] = $name;
    }

    foreach($this->options() as $value => $text) {
      $select->append($this->option($value, $text, $this->value() == $value));
    }

    $inner = new Brick('div');
    $inner->addClass('selectbox-wrapper');
    $inner->append($select);

    $wrapper = new Brick('div');
    $wrapper->addClass('input input-with-selectbox');
    $wrapper->append($inner);

    if($this->readonly()) {
      $wrapper->addClass('input-is-readonly');
    } else {
      $wrapper->attr('data-focus', 'true');
    }

    return $wrapper;
    
  }

}

In your blueprint with the select, you would then use this field instead of the select field:

treat_doctor:
        label: Behandelder Arzt
        type: addresses

If you want only the last name, you would need to split the field values in the custom field first. But maybe it’s better to have both first and last name to select from, in case the last names are not unique, anyway.

2 Likes

I just realized that the above code only generates a numeric key, but we want the names, so this bit

foreach($addresses as $address)  {
      $name = $address->addr_name();
      $this->options[] = $name;
    }

needs to be changed to

foreach($addresses as $address)  {
 $names[] = $address->addr_name;
}
 $this->options = array_combine($names, $names);

Maybe there is an easier way to achieve this, but at least it works:grin:

1 Like

THIS IS AWESOME! It works like a charm.
Thanks a lot!

Perhaps the number is even better for the output (array) of the rest of the address … I’ll see.

All the best,
Andreas

I think you need the name rather than a numeric value, otherwise you can’t find the item in the structure array.

To find the structure item that contains the selected name, you can use a little function:

<?php 
function findItem($addresses, $field, $value) {
   foreach($addresses as $key => $address) {
      if ( $address[$field] === $value )
         return $key;
   }
   return false;
}
$name = $page->treat_doctor()->value();
$addresses = page('addresses')->addresses()->yaml();
$index = findItem($addresses, 'addr_name', $name);
$address = $addresses[$index]; 
echo $address['addr_title']; //etc.
?>
1 Like