ex_admin
ex_admin copied to clipboard
Array type doesn't seem to allow clearing all options
When I clear the contents of a form array, an 'empty' array isn't posted back to the controller, so the clear doesn't happen. In fact, nothing is posted for the form value at all. This only happens when I'm removing every entry. Removing 1 of n works fine. Adding items works fine as well.
It appears that there's some javascript in here deciding not to post the empty results, but I'm having trouble tracking down where the problem is.
@jeffdeville Can you post your model and admin resource file? I need a bit more context to understand. Thanks...
Sure: Model
defmodule NHWeb.Customer do
use NHWeb.Web, :model
import Ecto.Query
alias NHWeb.{Licensee,License,Company,Repo}
schema "customers" do
field :name, :string
field :about, :string
field :website, :string
field :facebook, :string
field :twitter, :string
field :urls, {:array, :string}
field :video, :string
field :phones, {:array, :string} # unknown phone
field :office_phone, :string
field :mobile_phone, :string
field :fax, :string
field :featured_image, :string
field :images, {:array, :string}
field :valid, :boolean
field :review_status, :string
field :reviewed_by, :string
field :editor_notes, :string
has_many :customer_terms, NHWeb.CustomerTerm
has_many :licenses, NHWeb.License
belongs_to :company, NHWeb.Company
has_one :listing, NHWeb.Listing
# many_to_many :terms, NHWeb.Term, through: NHWeb.CustomerTerm
timestamps()
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name, :about, :website, :facebook,
:twitter, :video, :phones, :fax, :featured_image,
:images, :review_status, :reviewed_by, :editor_notes,
:urls])
|> cast_assoc(:customer_terms)
|> cast_assoc(:licenses)
|> cast_assoc(:company)
|> set_valid
|> validate_required([:name])
|> validate_inclusion(:review_status, ~w(new invalid in_process ready))
end
def set_valid(changeset) do
put_change(changeset, :valid, valid?(changeset))
end
defp valid?(changeset) do
do_valid?(Map.merge(changeset.data, changeset.changes))
end
defp do_valid?(%{featured_image: image}) when is_nil(image), do: false
defp do_valid?(%{featured_image: image}), do: String.length(image) > 0
defp do_valid?(_), do: false
# **************************************
# Move this to a context in 1.3 migration
# **************************************
@spec existing_licenses(list(map)) :: {:ok, list(NHVerify.License.t)}
def existing_licenses([]), do: {:ok, []}
def existing_licenses(licenses) do
# I guess I break these up by region, otherwise my 'in' queries are messy
region_lists = group_by_regions(licenses)
existing_region_licenses = region_lists
|> Enum.reduce(%{}, fn({region, license_ids}, acc) ->
query = from l in License,
where: l.region == ^region,
where: l.num in ^license_ids,
select: l
Map.put(acc, region, Repo.all(query))
end)
|> Enum.reduce([], fn({_, vals}, acc) -> acc ++ vals end)
{:ok, existing_region_licenses}
end
defp group_by_regions(licenses) do
licenses
|> Enum.reduce(%{}, fn (%{region: region, num: num}, acc) ->
Map.put(acc, region, Map.get(acc, region, []) ++ [num])
end)
end
end
Resource File
defmodule NHWeb.ExAdmin.Customer do
use ExAdmin.Register
import Ecto.Query
register_resource NHWeb.Customer do
scope :all
scope :new, fn(q) ->
from c in q,
where: c.review_status == "new"
end
scope :ready, fn(q) ->
from c in q,
where: c.review_status == "ready"
end
index do
selectable_column()
column :id
column :name
column :website
column :phones
column :office_phone
column :featured_image
# column :licenses, fields: [:num]
column :review_status
column :reviewed_by
end
form customer do
inputs do
input customer, :name
input customer, :about, type: :text
input customer, :website
input customer, :facebook
input customer, :twitter
input customer, :urls
input customer, :video
input customer, :phones
input customer, :office_phone
input customer, :mobile_phone
input customer, :fax
input customer, :featured_image
input customer, :images
input customer, :editor_notes, type: :text
end
end
member_action :ready, &__MODULE__.ready_action/2, label: "Ready!"
def ready_action(conn, params) do
current_user = conn.assigns.current_user
# changeset_fn = Customer.changeset_fn(defn, :update)
updated_params = %{review_status: "ready", reviewed_by: current_user.email}
customer = NHWeb.Repo.get(NHWeb.Customer, params[:id])
changeset = NHWeb.Customer.changeset(customer, updated_params)
case NHWeb.Repo.update(changeset) do
{:error, changeset} ->
Phoenix.Controller.put_flash(conn, :error, "Customer could not be updated.")
{:ok, resource} ->
Phoenix.Controller.put_flash(conn, :notice, "Customer was successfully updated.")
end
|> Phoenix.Controller.redirect(to: ExAdmin.Utils.admin_resource_path(conn, :index))
end
end
end
And here's a screenshot. If I try and delete this phone number, it won't work, because the phones field isn't posted with the params

Ok, I get how. Thanks for posting. I believe your best bet is to handle this in your changeset. If the data in the changeset has something different than the params, you know its a delete and could add a change to the changeset.
What do you think?
@smpallen99 The downside to that is that you would have to send back the current array with every single update, which isn't very REST-y.
I guess this works with HTML responders, but for this to be "correct", the client should only patch changed values. In this case, the empty array should be sent with the data.
(Just my unsolicited 2¢)
I need to look a little deeper into this, but not tonight.
seems to be quick fixed in changeset with this code
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:title, :section, :array1, :array2, :order])
|> put_change(:array1, Map.get(params, "array1", []))
|> put_change(:array2, Map.get(params, "array2", []))
end
@d4rk5eed your solution won't work, as if we call the changeset like on action edit, the params of that field be always be set to [], and when you just get to edit form, you can't see your selected value because it's always be blank