Answers.Body: <p>Something like this (Let's call the fieldtype Geo):</p>
  
  <p>Your field html should output those two fields, and update a hidden input with the correct namespaced fieldname. Get it like this:</p>
  
  <pre><code>$id = craft()-&gt;templates-&gt;formatInputId($name);
  $namespaceInputId = craft()-&gt;templates-&gt;namespaceInputId($id);
  </code></pre>
  
  <p><a href="http://buildwithcraft.com/docs/plugins/field-types#binding-javascript" rel="nofollow">See docs here about binding JS to fields.</a></p>
  
  <p>Your fieldtypes content should be defined as Mixed. Craft will encode/decode it to JSON when saving the model automatically.</p>
  
  <pre><code>public function defineContentAttribute()
  {
      return AttributeType::Mixed;
  }
  </code></pre>
  
  <p>In your fieldtypes prepValueFromPost method, you do all the conversion magic for saving. Let's say your JS save the lat/lng values as a pipe separated value in the hidden input field.</p>
  
  <pre><code>public function prepValueFromPost($value)
  {
      if ( empty($value) )
      {
          return new Geo_GeoModel();
      }
  
      $coordinates = explode('|', $value);
      $geo = new Geo_GeoModel($coordinates);
      return $geo;
  }
  </code></pre>
  
  <p>You also need to hook up the model with the defined attributes:</p>
  
  <pre><code>class Geo_GeoModel extends BaseModel
  {
      protected function defineAttributes()
      {
          return array(
              'lat' =&gt; AttributeType::String,
              'lng' =&gt; AttributeType::String,
          );
      }
  
      public function render()
      {
          $render = craft()-&gt;templates-&gt;render('geo/templates/render', $this);
          return $render;
      }
  
      public function __toString()
      {
          return $this-&gt;render();
      }
  }
  </code></pre>
  
  <p>I was actually going to make a plugin that does the same. Please share if you do :)</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-17T05:32:03.443Z
Answers.Text: Hey Fred, you may have already seen this, but I built a plugin which contains those fields (and more)... https://www.doublesecretagency.com/plugins/smart-map/docs/using-an-address-field
Answers.UserDisplayName: Lindsey D
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-17T13:32:42.443Z
Answers.Text: Excellent!  JS and a hidden input were exactly what I was thinking, but I wasn't sure if that was the "right" way to do it.
Answers.UserDisplayName: Angela T
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-16T21:48:07.027Z
Answers.LastActivityDate: 2014-09-17T09:46:14.567Z
Answers.LastEditDate: 2014-09-17T09:46:14.567Z
Answers.UserDisplayName: Fred Carlsen
Answers.Body: <p>You can do this simply by setting your field type’s <a href="http://buildwithcraft.com/classreference/fieldtypes/IFieldType#defineContentAttribute-detail">defineContentAttribute()</a> method to return <code>AttributeType::Mixed</code>, which will tell Craft to JSON-encode its value before storing it in the database.</p>
  
  
  
  <pre class="lang-php prettyprint-override"><code>public function defineContentAttribute()
  {
      return AttributeType::Mixed;
  }
  </code></pre>
  
  <p>Then, whatever you submit in the field’s post data will be saved as-is.</p>
  
  <p>For example, if your <a href="http://buildwithcraft.com/classreference/fieldtypes/IFieldType#getInputHtml-detail">getInputHtml()</a> method had this:</p>
  
  <pre class="lang-php prettyprint-override"><code>public function getInputHtml($name, $value)
  {
      $lat = (isset($value['lat']) ? $value['lat'] : '');
      $lng = (isset($value['lng']) ? $value['lng'] : '');
  
      return '&lt;input type="text" name="'.$name.'[lat]" value="'.$lat.'"&gt;' .
             '&lt;input type="text" name="'.$name.'[lng]" value="'.$lng.'"&gt;';
  }
  </code></pre>
  
  <p>Then it would be expected that the resulting post data for your field would look something like:</p>
  
  <pre class="lang-php prettyprint-override"><code>array(
      'lat' =&gt; '12345',
      'lng' =&gt; '67890'
  )
  </code></pre>
  
  <p>And with <code>AttributeType::Mixed</code>, that’s exactly how it would get stored. Behind the scenes it will get JSON-encoded when getting saved to the DB, and JSON-decoded when getting fetched from the DB, but your field type will never need to know about that.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-10-09T19:26:09.737Z
Answers.Text: Thanks!  I wasn't aware of the `Mixed` attribute type when I posted this. Looks like the JS and the hidden field was extraneous.
Answers.UserDisplayName: Angela T
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-10-09T16:15:38.707Z
Answers.LastActivityDate: 2014-10-09T16:15:38.707Z
Answers.UserDisplayName: Brandon Kelly
Body: <p>I'd like to create a field type for my plugin called "location" with two text boxes: one that holds a coordinate for latitude, and one for longitude. I haven't figured out yet how to map those two values from HTML input elements in a template to a JSON array in the database.  Is there an elegant way to achieve this with the Craft API?  </p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2014-09-17T05:27:36.360Z
Comments.Text: Not sure if you've seen this, but I've already built a plugin that has those fields (and more)... https://www.doublesecretagency.com/plugins/smart-map/docs/using-an-address-field
Comments.UserDisplayName: Lindsey D
Tags: <plugin-development><fieldtypes><custom-fieldtype>
Title: Custom Field Type with Multiple Values
ThreadText: # Custom Field Type with Multiple Values
  
  (Asked by: username_0 on 2014-09-16)
  
  I'd like to create a field type for my plugin called "location" with two text boxes: one that holds a coordinate for latitude, and one for longitude. I haven't figured out yet how to map those two values from HTML input elements in a template to a JSON array in the database. Is there an elegant way to achieve this with the Craft API?
  
  **Tags:** plugin-development, fieldtypes, custom-fieldtype
  
  > **Comments:**
  > **username_1**: Not sure if you've seen this, but I've already built a plugin that has those fields (and more)... https://www.doublesecretagency.com/plugins/smart-map/docs/using-an-address-field  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_3 on 2014-10-09. Score: 6 | Accepted answer
  
  You can do this simply by setting your field type’s [defineContentAttribute()](http://buildwithcraft.com/classreference/fieldtypes/IFieldType#defineContentAttribute-detail) method to return `AttributeType::Mixed`, which will tell Craft to JSON-encode its value before storing it in the database.
  
  ```php
  public function defineContentAttribute()
  {
      return AttributeType::Mixed;
  }
  
  ```
  
  Then, whatever you submit in the field’s post data will be saved as-is.
  
  For example, if your [getInputHtml()](http://buildwithcraft.com/classreference/fieldtypes/IFieldType#getInputHtml-detail) method had this:
  
  ```php
  public function getInputHtml($name, $value)
  {
      $lat = (isset($value['lat']) ? $value['lat'] : '');
      $lng = (isset($value['lng']) ? $value['lng'] : '');
  
      return '<input type="text" name="'.$name.'[lat]" value="'.$lat.'">' .
             '<input type="text" name="'.$name.'[lng]" value="'.$lng.'">';
  }
  
  ```
  
  Then it would be expected that the resulting post data for your field would look something like:
  
  ```php
  array(
      'lat' => '12345',
      'lng' => '67890'
  )
  
  ```
  
  And with `AttributeType::Mixed`, that’s exactly how it would get stored. Behind the scenes it will get JSON-encoded when getting saved to the DB, and JSON-decoded when getting fetched from the DB, but your field type will never need to know about that.
  
  > **Comments:**
  > **username_0**: Thanks!  I wasn't aware of the `Mixed` attribute type when I posted this. Looks like the JS and the hidden field was extraneous.  
  
  ---
  
  ### Answer by username_2 on 2014-09-16. Score: 3
  
  Something like this (Let's call the fieldtype Geo):
  
  Your field html should output those two fields, and update a hidden input with the correct namespaced fieldname. Get it like this:
  
  ```
  $id = craft()->templates->formatInputId($name);
  $namespaceInputId = craft()->templates->namespaceInputId($id);
  
  ```
  
  [See docs here about binding JS to fields.](http://buildwithcraft.com/docs/plugins/field-types#binding-javascript)
  
  Your fieldtypes content should be defined as Mixed. Craft will encode/decode it to JSON when saving the model automatically.
  
  ```
  public function defineContentAttribute()
  {
      return AttributeType::Mixed;
  }
  
  ```
  
  In your fieldtypes prepValueFromPost method, you do all the conversion magic for saving. Let's say your JS save the lat/lng values as a pipe separated value in the hidden input field.
  
  ```
  public function prepValueFromPost($value)
  {
      if ( empty($value) )
      {
          return new Geo_GeoModel();
      }
  
      $coordinates = explode('|', $value);
      $geo = new Geo_GeoModel($coordinates);
      return $geo;
  }
  
  ```
  
  You also need to hook up the model with the defined attributes:
  
  ```
  class Geo_GeoModel extends BaseModel
  {
      protected function defineAttributes()
      {
          return array(
              'lat' => AttributeType::String,
              'lng' => AttributeType::String,
          );
      }
  
      public function render()
      {
          $render = craft()->templates->render('geo/templates/render', $this);
          return $render;
      }
  
      public function __toString()
      {
          return $this->render();
      }
  }
  
  ```
  
  I was actually going to make a plugin that does the same. Please share if you do :)
  
  > **Comments:**
  > **username_1**: Hey username_2, you may have already seen this, but I built a plugin which contains those fields (and more)... https://www.doublesecretagency.com/plugins/smart-map/docs/using-an-address-field  
  > **username_0**: Excellent!  JS and a hidden input were exactly what I was thinking, but I wasn't sure if that was the "right" way to do it.  
  
  ---
  
  