技术控

    今日:91| 主题:49531
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Dynamic forms with Phoenix

[复制链接]
岁月悠长 发表于 2016-9-30 09:35:52
155 2

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
Today we will learn how to build forms in Phoenix that use our schema information to dynamically show the proper input fields with validations, errors and so on. We aim to support the following API in our templates:
  [code]<%= input f, :name %>
<%= input f, :address %>
<%= input f, :date_of_birth %>
<%= input f, :number_of_children %>
<%= input f, :notifications_enabled %>[/code]   Each generated input will have the proper markup and classes (we will use Bootstrap in this example), include the proper HTML attributes, such as required for required fields and validations, and show any input error.
  The goal is to build this foundation in our own applications in very few lines of code, without 3rd party dependencies, allowing us to customize and extend it as desired as our application changes.
  Setting up

   Before building our input helper, let’s first generate a new resource which we will use as a template for experimentation (if you don’t have a Phoenix application handy, run mix phoenix.new your_app before the command below):
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean[/code]  Follow the instructions after the command above runs and then open the form template at “web/templates/user/form.html.eex”. We should see a list of inputs such as:
  [code]

  <%= label f, :address, class: "control-label" %>
  <%= text_input f, :address, class: "form-control" %>
  <%= error_tag f, :address %>
[/code]   The goal is to replace each group above by a single <%= input f, field %> line.
  Adding changeset validations

  Still in the “form.html.eex” template, we can see that a Phoenix form operates on Ecto changesets:
  [code]<%= form_for @changeset, @action, fn f -> %>[/code]   Therefore, if we want to automatically show validations in our forms, the first step is to declare those validations in our changeset. Open up “web/models/user.ex” and let’s add a couple new validations at the end of the changeset function:
  [code]|> validate_length(:address, min: 3)
|> validate_number(:number_of_children, greater_than_or_equal_to: 0)[/code]   Also, before we do any changes to our form, let’s start the server with mix phoenix.server and access http://localhost:4000/users/new to see the default form at work.
   Writing the input function

   Now that we have set up the codebase, we are ready to implement the input function.
   The YourApp.InputHelpers module

   Our input function will be defined in a module named YourApp.InputHelpers (where YourApp is the name of your application) which we will place in a new file at “web/views/input_helpers.ex”. Let’s define it:
  [code]defmodule YourApp.InputHelpers do
  use Phoenix.HTML

  def input(form, field) do
    "Not yet implemented"
  end
end[/code]   Note we used Phoenix.HTML at the top of the module to import the functions from  the Phoenix.HTML project  . We will rely on those functions to build the markup later on.
   If we want our input function to be automatically available in all views, we need to explicitly add it to the list of imports in the “def view” section of our “web/web.ex” file:
  [code]import YourApp.Router.Helpers
import YourApp.ErrorHelpers
import YourApp.InputHelpers # Let's add this one
import YourApp.Gettext[/code]   With the module defined and properly imported, let’s change our “form.html.eex” function to use the new input functions. Instead of 5 “form-group” divs:
  [code]

  <%= label f, :address, class: "control-label" %>
  <%= text_input f, :address, class: "form-control" %>
  <%= error_tag f, :address %>
[/code]  We should have 5 input calls:
  [code]<%= input f, :name %>
<%= input f, :address %>
<%= input f, :date_of_birth %>
<%= input f, :number_of_children %>
<%= input f, :notifications_enabled %>[/code]  Phoenix live-reload should automatically reload the page and we should see “Not yet implemented” appear 5 times.
  Showing the input

   The first functionality we will implement is to render the proper inputs as before. To do so, we will use  the Phoenix.HTML.Form.input_type function  , that receives a form and a field name and returns which input type we should use. For example, for :name , it will return :text_input . For :date_of_birth , it will yield :datetime_select . We can use the returned atom to dispatch to Phoenix.HTML.Form and build our input:
  [code]def input(form, field) do
  type = Phoenix.HTML.Form.input_type(form, field)
  apply(Phoenix.HTML.Form, type, [form, field])
end[/code]  Save the file and watch the inputs appear on the page!
  Wrappers, labels and errors

  Now let’s take the next step and show the label and error messages, all wrapped in a div:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean0[/code]   We used content_tag to build the wrapping div and the existing YourApp.ErrorHelpers.error_tag function that Phoenix generates for every new application that builds an error tag with proper markup.
  Adding Bootstrap classes

  Finally, let’s add some HTML classes to mirror the generated Bootstrap markup:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean1[/code]  And that’s it! We are now generating the same markup that Phoenix originally generated. All in 14 lines of code. But we are not done yet, let’s take things to the next level by further customizing our input function.
  Customizing inputs

  Now that we have achieved parity with the markup code that Phoenix generates, we can further extend it and customize it according to our application needs.
  Colorized wrapper

   One useful UX improvement is to, if a form has errors, automatically wrap each field in a success or error state accordingly. Let’s rewrite the wrapper_opts to the following:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean2[/code]   And define the private state_class function as follows:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean3[/code]  Now submit the form with errors and you should see every label and input wrapped in green (in case of success) or red (in case of input error).
  Input validations

   We can use  the Phoenix.HTML.Form.input_validations function  to retrieve the validations in our changesets as input attributes and then merge it into our input_opts . Add the following two lines after the input_opts variable is defined (and before the content_tag call):
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean4[/code]  After the changes above, if you attempt to submit the form without filling the “Address” field, which we imposed a length of 3 characters, the browser won’t allow the form to be submitted. Not everyone is a fan of browser validations and, in this case, you have direct control if you want to include them or not.
   At this point it is worth mentioning both Phoenix.HTML.Form.input_type and Phoenix.HTML.Form.input_validations are defined as part of the Phoenix.HTML.FormData protocol. This means if you decide to use something else besides Ecto changesets to cast and validate incoming data, all of the functionality we have built so far will still work. For those interested in learning more, I recommend checking out  the Phoenix.Ecto project  and learn how the integration between Ecto and Phoenix is done by simply implementing protocols exposed by Phoenix.
  Per input options

   The last change we will add to our input function is the ability to pass options per input. For example, for a given input, we may not want to use the type inflected by input_type . We can add options to handle those cases:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean5[/code]   This means we can now control which function to use from Phoenix.HTML.Form to build our input:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean6[/code]   We also don’t need to be restricted to the inputs supported by Phoenix.HTML.Form . For example, if you want to replace the :datetime_select input that ships with Phoenix by a datepicker, you can wrap the input creation into an function and pattern match on the inputs you want to customize.
   Let’s see how our input functions look like with all the features so far, including support for custom inputs (input validations have been left out):
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean7[/code]  And then in your template:
  [code]mix phoenix.gen.html User users name address date_of_birth:datetime number_of_children:integer notifications_enabled:boolean8[/code]  Since your application owns the code, you will always have control over the inputs types and how they are customized. Luckily Phoenix ships with enough functionality to give us a head start, without compromising our ability to refine our presentation layer later on.
  Summing up

   This article showed how we can leverage the conveniences exposed in Phoenix.HTML to dynamically build forms using the information we have already specified in our schemas. Although the example above used the User schema, which directly maps to a database table, Ecto 2.0 allows us to use schemas to map to any data source , so the input function can be used for validating search forms, login pages, and so on without changes.
   While we have developed projects such as Simple Form to tackle those problems in our Rails projects, with Phoenix we can get really far using the minimal abstractions that ship as part of the framework, allowing us to get most of the functionality while having full control over the generated markup.
   
Dynamic forms with Phoenix-1 (phoenix,the,phoenix,phoenix,os,phoenixsuit,phoenix,marie)

友荐云推荐




上一篇:Strata AI 纽约大会热点回顾(1)
下一篇:外媒速递:Web开发人员不容错过的十款最佳免费JavaScript框架
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

不想走啊 发表于 2016-9-30 10:13:00
楼下的不要小看我,我可不是吃素的。
回复 支持 反对

使用道具 举报

姜丽萍 发表于 2016-9-30 11:43:17
火前留名,前排占座,此楼出租,欢迎议价。
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表