<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>

CC BY-SA 3.0
2014-09-17T05:32:03.443Z
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
Lindsey D
CC BY-SA 3.0
2014-09-17T13:32:42.443Z
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.
Angela T
CC BY-SA 3.0
2014-09-16T21:48:07.027Z
2014-09-17T09:46:14.567Z
2014-09-17T09:46:14.567Z
Fred Carlsen
<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>

CC BY-SA 3.0
2014-10-09T19:26:09.737Z
Thanks!  I wasn't aware of the `Mixed` attribute type when I posted this. Looks like the JS and the hidden field was extraneous.
Angela T
CC BY-SA 3.0
2014-10-09T16:15:38.707Z
2014-10-09T16:15:38.707Z
Brandon Kelly
<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>

CC BY-SA 3.0
2014-09-17T05:27:36.360Z
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
Lindsey D
<plugin-development><fieldtypes><custom-fieldtype>
Custom Field Type with Multiple Values
# 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() method to return AttributeType::Mixed, which will tell Craft to JSON-encode its value before storing it in the database.
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() method had this:
public function getInputHtml($name, $value)
{
    $lat = (isset($value['lat']) ? $value['lat'] : '');
    $lng = (isset($value['lng']) ? $value['lng'] : '');

    return '' .
           '';
}

Then it would be expected that the resulting post data for your field would look something like:
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.
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 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  
> **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.  

---

