代码之家  ›  专栏  ›  技术社区  ›  just mike

如何从一个地方控制HTML表单域的定义、表示、验证和存储?

  •  4
  • just mike  · 技术社区  · 16 年前

    我希望能够在一个地方定义关于表单字段的所有内容,而不是在数据库中、一些在HTML中、一些在JavaScript中、一些在ASP中……

    当我想改变一个领域的东西时,为什么我要担心可能在四个不同的地方(或更多)改变东西?

    也就是说,我不想:

    • 在数据库中声明字段
    • 和 在HTML中的某个地方复制一些信息
    • 和 在某个javascript中复制更多信息
    • 和 在某个ASP中复制更多信息

    因为我是一个开发人员,所以我理想地寻找的是方法论,而不是工具或S/W包。(我想!)

    目前 ,我通过将所有控制信息放入SQL的扩展属性“description”文本区域来实现这一点。例如,所需的电话号码字段将具有以下SQL声明:

    [home_phone] [varchar](15) NOT NULL

    我在描述扩展属性中放置了以下“控件”:

    ["Home Phone"][phone_text][user_edit][required][allow_na][form_field_size_equals_size][default=""][group="home_address"][rollover="enter only: numbers, dash, parenthesis, space"][explanation="enter <strong>n/a</strong> if you don't have a home phone"]

    在我当前的系统中,以下HTML是为家庭电话字段动态生成的:

    <div class="div-item" id="item-FORM:FIELD:TABLE_HOME:HOME_PHONE">
        <div class="div-item-description" id="item_description-FORM:FIELD:TABLE_HOME:HOME_PHONE">
            <span class="rollover-explanation" title="enter only: numbers, dash, parenthesis, space">
                <label for="FORM:FIELD:TABLE_HOME:HOME_PHONE" id="item_label-FORM:FIELD:TABLE_HOME:HOME_PHONE">
                    Home Phone
                </label>
            </span>
        </div>
        <div class="div-item-stipulation" id="item_stipulation-FORM:FIELD:TABLE_HOME:HOME_PHONE">
            <span class="stipulation-required" id="item_stipulation_span-FORM:FIELD:TABLE_HOME:HOME_PHONE" title="required" >
                *
            </span>
        </div>
        <div class="div-item-value" id="item_value-FORM:FIELD:TABLE_HOME:HOME_PHONE">
            <div class="individual-forms">
                <form class="individual-forms" id="FORM:TABLE_HOME:HOME_PHONE" name="FORM:TABLE_HOME:HOME_PHONE" action="" method="post" enctype="multipart/form-data" onsubmit="return(false);">
                    <div class="individual-forms-element">
                        <input
                         class=""
                         type="text"
                         id="FORM:FIELD:TABLE_HOME:HOME_PHONE" name="FORM:FIELD:TABLE_HOME:HOME_PHONE"
                         size="15" maxlength="15"
                         value=""
                            FORM_control="true"
                            FORM_control_name="Home Phone"
                            FORM_control_is_required="true"
                            FORM_control_is_phone_text="true"
                        >
                    </div>
                </form>
            </div>
        </div>
        <span class="spanExplanation">
            enter <strong>n/a</strong> if you don't have a home phone
        </span>
    </div>
    

    它看起来像这样(在IE 7中):

    html form field - phone number example

    客户端javascript验证由 **FORM_control**... 参数,错误时产生解释和字段突出显示。(不幸的是,HTML元素中的自定义参数并不完全符合标准。)

    我的主要问题 使用描述字段的方法在使用和维护时总是很麻烦。description属性只能是255个字符,所以我有很多缩写。随着系统的扩展,控制的数量也大大超过了原来的十几个。我解释所有这些控件及其缩写的代码并不美观或有效。 和 如我所说,HTML元素中的自定义参数在Firefox中不起作用。

    我目前正在控制(并希望继续控制)的内容包括:

    • 字段描述(例如“家庭电话号码”)。
    • 数据库表名(例如,“家庭地址”)。
    • 数据库字段名(例如,“家庭电话”)。
    • 数据库字段类型/大小
    • 数据库允许空值
    • 分组(例如,此特定字段是所有“主”字段的一部分)
    • 必需/可选
    • 只读(用于系统提供的数据)
    • 大小(显示的表单域大小)
    • 类型(例如,文本、数字、字母、选择、邮政编码、电话、街道地址、姓名、日期等)
    • 接受的输入(非空;仅限数字;无空格;电话号码;注册表项等)
    • 扩展解释(例如,对于电话“如果没有家庭电话,请输入N/A”)。
    • 滚动说明(例如,对于电话“仅输入:数字、破折号、括号、空格”)。
    • 行(对于选择列表--1=下拉列表)
    • 行/列(用于文本区域)
    • 错误消息文本
    • 错误指示(如何显示包含错误的字段,例如红色背景)
    • 等。。。

    很明显,我完全赞成逻辑和设计元素的分离。我有一个单独的CSS文件,它是手动维护的(不是生成过程的一部分)。

    我的服务器环境是经典的(非.NET)ASP和SQL 2008。我很擅长HTML、CSS、JavaScript和ASP,我也很熟悉SQL。

    我怎么想的? 我想要 是某种类型的JSON、XML等,它是用于生成所有内容的单一源,例如:

    • 实际创建SQL表的SQL脚本
    • HTML(使用CSS类和JavaScript客户端验证/函数调用)
    • ASP(服务器端验证)

    我目前的方法是动态的(不是编译的),速度很慢,所以我可能正在寻找某种“编译器”,它只生成一次这些东西。我真的只有经典的ASP、JavaScript或SQL作为这个“编译器”的可用语言。

    虽然我认为我可以自己创建这个系统,但我希望其他更好的开发人员已经想出了类似的方法。

    假设这至少可以扩展到几十个字段。(仅供参考,我当前的表单在一页上有太多字段,但我要单独解决这个问题。)

    谢谢你的帮助!

    7 回复  |  直到 16 年前
        1
  •  2
  •   SpliFF    16 年前

    javascript验证被高估了

    我认为Javascript验证被高估了。在服务器往返可能需要10秒,但现在通常不到3秒的情况下,这很好。考虑到Ajax提交过程,可以将时间缩短到亚秒。

    作为回报,您必须处理跨浏览器支持的各种复杂性、复杂的调试、缺少服务器端日志记录以及处理用户禁用JS的情况。在一个典型的场景中,我们谈论的是大量的浪费时间和调试困难(试着问一个典型的白痴他们使用什么浏览器,更不用说什么 版本 他们正在使用)。

    数据库作为一站式验证器

    你说数据库不是一个完整的验证环境,但我认为这不再是真的了。像postgresql这样的现代数据库将允许您将复杂的验证函数作为触发器挂接在您选择的语言中,并向应用程序返回适当的错误响应。

    因此,如果您按照我要到的地方,可以在一个地方验证数据库,而不存在历史缺陷。过程是:

    1. 创建一个基本的HTML表单,忘记 HTML5或JavaScript验证。
    2. 当表格完成时,或 需要,通过Ajax提交(如果 可用)或标准岗位。
    3. 或多或少地传递更新/插入 直接到数据库 触发函数正常化和 验证数据。
    4. 立即返回结果和或 错误(可能通过一个事务) 执行任何进一步的服务器 在此阶段处理。如果你 决定不保留数据 可以删除新行或 回滚事务。
    5. 在结论返回任何适当的 重定向、消息或更新到 通过json/ajax或 用清除的数据重新加载。

    这听起来可能缓慢/低效,但我认为这忽略了当今的现实,即:

    1. 现在几乎所有东西都是宽带的,甚至无线的。
    2. 处理能力比 显影时间。
    3. 这类 更新往往受到 快速的用户填写表单,你不会 把你的数据库打成一个典型的 脚本。
    4. 你还得做验证 在某处 那么为什么数据库不呢?

    而且好处是巨大的:

    1. 在大容量服务器(如Exchange、Twitter、Feed等)上, 进程用于API控件 通过soap/ajax/rss/whatever-since 只需要一层薄薄的 在API客户端之间传输数据 以及数据库。
    2. 不管什么客户 使用语言或协议 验证保持不变。
    3. 即使原始SQL语句 可防止 编程错误,损坏 从导入或第三方源 破坏数据结构。
    4. 如果 必修的。在普通代码中,这通常更难。
    5. 验证总是一致的。
    6. 验证函数位于 数据库,然后允许访问 索引和其他行或表 连接器开销,数据转换 以及网络/插座延迟。
    7. 验证函数可以在中运行 编译的代码,即使你的网站 服务器语言是动态的。

    唯一真正的缺点是:

    1. 难以升级或迁移到 其他数据库软件。
    2. 如果你喜欢的语言很难 不支持(但是Postgres 支持用C编写的函数, PL/PGSQL,Python,TCL,Perl,Java, r、ruby、scheme、bash和php,所以 除非你被卡在C/VB上 应该找一个你能处理的)。

    上下文敏感性

    你的问题有些方面我根本不推荐。主要是在一个位置将HTML表单对象的表示与数据绑定在一起。

    这个想法很快就会适得其反,因为您会发现在典型的应用程序中,信息的表示对上下文(特别是目标受众)非常敏感。

    例如,在订购系统上,可能有客户机输入的数据,然后管理员可以访问这些数据。客户机视图中的数据可能更为有限,可能需要不同的标题和描述,最好显示为复选框,而管理员可以获得更紧凑的视图。您甚至可能向不同类型的客户展示相同的数据(零售与批发)。

    简言之,数据的呈现通常需要比其验证更具流动性,因此在某一点上,您应该真正画出一条线——即使这意味着一些重复。

        2
  •  1
  •   Thom Smith    16 年前

    我一直在努力 确切地 我的工作也有同样的问题。我不能忍受重复我自己,尤其是因为我知道,当我必须在几个月后改变一些事情时,我永远不会记得所有零散的多余部分。答案必须考虑以下事实:

    • 数据库应尽可能合理地进行自我验证。这是基本的数据完整性;如果您试图将无效数据放入其中,DB应该抛出一个fit。

    • 数据库无法验证自身。很容易为唯一性、格式或外键添加约束,从技术上讲,SQL可以做得更进一步,但是如果您在数据库级别强制执行地址/邮政编码对应,您会后悔的。验证逻辑的某些部分必须存在于服务器端代码中。在你我的案例中,这意味着ASP。

    • 如果您想要客户端验证,这意味着JavaScript。

    此时,我们已经在讨论 三种语言 以及它们之间的阻抗失配可能是显著的。您不能总是将验证因素考虑到其中之一。你所能做的就是尽可能地把逻辑联系在一起。

    你建议的解决方案有一个巨大的优势,即所有的逻辑都在一个地方,在一起。这一优势由以下几个缺点来平衡:

    • 如果不与数据库通信,就无法进行任何验证。

    • 为了将元数据从数据库获取到ASP,必须有特殊的代码来解释元数据的微型语言。这比接受某种程度的冗余要复杂得多。

    • 元数据将前端显示代码放入数据库中。这意味着,如果要更改文本,必须编辑数据库模型。这是一个相当激烈的需求,它将您的数据库模型与表示逻辑联系起来。此外,国际化几乎是不可能的。

    • 因为在元数据和用户之间有如此多的转换层,所以对元数据空间的任何扩展都需要修改几个紧密耦合的代码层。

    为了在您的解决方案和它设计用来避免的冗余之间找到一个中间地带,我建议如下:

    • 在数据库中放入基本的验证约束。

    • 在ASP中创建一个系统,用于指定具有任意内容和验证约束的行为数据模型。使用此语法定义模型时,将只复制数据库中的裸骨约束。

    • 在ASP中创建一个系统,以HTML形式在页面上显示表单字段。表单字段声明将引用适当的数据模型,并另外包括显示代码,如标签和描述性文本。HTML生成代码可以使用从数据模型派生的合理默认值。唯一重复的数据应该是字段的名称,该名称用作将显示的字段绑定到适当的数据模型的键。

    • 创建或查找javascript验证库。让前面提到的HTML生成代码根据关联的数据模型自动将钩子插入到生成的标记中的这个库中。

    因此,您有一个系统,根据字段最合适的位置,可以将有关字段的信息存储在少数位置,但几乎不重复。验证信息在ASP数据模型中声明。显示信息仅在“on page”字段声明中找到。字段名在整个堆栈中用作将它们链接在一起的键,并且关注的层次结构允许您根据需要覆盖在较低级别上所做的假设。

    我还在研究这个设计的实现,但是如果您感兴趣,我可以发布一些示例代码。

        3
  •  0
  •   bpeterson76    16 年前

    在我看来,这违背了逻辑和设计元素分离的每一个原则。我知道在我从事的更大的项目中,有一些实际的SDLC需求要求一种类型的工程师可以接触到一个级别的文件,而一个UI工程师可以接触到另一个,而“代码猴子”只能接触到其中的一个子集。你能想象在那种情况下会发生的混乱吗?代码猴子必须得到用户界面工程师的许可,而用户界面工程师则必须与工程师协调,工程师必须与集成部门一起参加电话会议,集成部门必须与技术支持部门保持联系,然后由技术支持部门搁置项目,直到业务部门要求合法为止。

    别开玩笑了,我认为你的方法不错。

    我确实相信按照本机处理的方式来处理事情,即构建表单文本字段可能比通过一系列脚本构建HTML的数据库调用更有效地由HTML本机处理。您的“已编译”方法让我想知道它是否会取消在各自文件中缓存常见javascript和css元素的好处。

    有一些框架,如Zend、CodeIgniter和Symfony(在PHP方面),通过内置功能越来越接近于您提到的内容……尽管它们还没有出现。Zend特别使用编程特性来构建、验证和设计表单,一旦你发现它的细微差别,它就非常强大。也许它可以作为你终极探索的典范。虽然看起来你是一个典型的ASP用户,但这不是你想要的。我离题了。

        4
  •  0
  •   Tarik    16 年前

    我认为这个问题超出了我的知识范围,但我认为尝试和帮助并没有什么坏处。

    我正在我的第一个PHP站点上工作,从一开始,由于我不能预测站点的许多因素,而且只有一个人,所以我从一开始就决定每个页面上的每个设计元素都可以通过一个页面来维护。这是一次学习经历,所以我不太担心没有太多的计划,但有些事情只是磨磨我的齿轮,比如命名约定,但是用我的方法,我总是能够轻松地对整个站点进行更改。

    我制作的每一页的结构都是这样的:

    <?php require_once 'constants.php'; ?>
    <?php $pageTitle = 'Home Page'; ?>
    <?php require_once REF_LAYOUT_TOP; ?>
    
    <h1>Hello!</h1>
    
    <p>World</p>
    
    <?php require_once REF_LAYOUT_BOTTOM; ?>
    

    在常数中,几乎所有的东西都有常数。CSS颜色(用于一致的布局)、目录位置、数据库连接、链接、仅用于特定页面的常量(这样我就可以修改文件名,而不会损坏任何内容)以及各种各样的东西。

    顶部部分包含导航、错误处理javascript脚本、任何类型的动态创建内容、导航等。

    这样,如果我想实现一些新的东西,它可以在任何地方实现。我给了jquery一次机会,它只需要一个链接。

    可能的解决方案

    如果您试图从一个位置调整很多东西,我强烈建议您投资一些PHP知识。因为PHP只是一个服务器脚本,所以它的唯一输出是文本。换句话说,您可以在JavaScript、HTML和任何地方插入PHP。这就是如何为各种悬停弹出窗口设置相同的文本。我不知道ASP是否会阻止你这样做(我对此一无所知)。

    我想这就是大多数网站的构建方式。必须是…他们还能怎么维护数百页呢?我认为这是最符合逻辑和语义的。

        5
  •  0
  •   rovaughn    16 年前

    我不熟悉ASP,所以我将更一般地讲,而不知道它们是如何实现的。

    通常,表单表示创建、编辑或删除实体所需的信息。所以我从一个实体类开始。在其他体系结构中,这通常称为模型(在模型视图控制器中)。实体类确定它需要什么信息,它负责数据库查询。

    可以通过这种方式直接从实体构建表单。实体提供了更直接的控制,例如,数据库中可能有一个整型字段,但您真正需要的值介于0和255之间。实体可以知道这个更具体的约束,即使数据库不知道。

    接下来,您可以创建某种类型的表单类,该类将使用实体来生成其接口。它将处理所有HTML、JavaScript以及您需要的其他内容。

    实体可以有多种类型。数据库中的表示可以有效地分离。假设一个帖子可以有很多标签。在数据库中,您可能会保留两个表,一个用于日志,另一个用于标记。但是这个实体将代表一个帖子,以及一个标签列表,所以它们不是分开的。

    表单类可以处理它的外观,您只需要担心语义。例如,如果实体调用一个字符串列表,那么表单可以通过使用javascript创建一个扩展的文本字段列表来实现,然后表单负责将这些数据正确提交给实体。

    表单还将在多个字段一起工作或解析中产生差异。例如,如果表单看到一个可以为空的类型,它将提供一个解释,说明“如果没有电话号码,请键入n/a”,如果看到该字符串,请正确返回空值。

    类型类可以是用于验证表单数据的接口。如果所有类型上的validate()方法都返回true,则提交表单。每种类型还负责解析其值(如“n/a”解析),以便提交正确的内容。

    其中一点是表单与表不相似。表中的ID字段不应该出现在表单中,并且某些数据可能在另一个表中与之相连,因此请根据它正在建模的“实体”来考虑表单,而不是表。它只是一个适配器。

        6
  •  0
  •   jeff    16 年前

    我为XML文件中的每个表定义了我的模式。然后我编写了一组CRUD方法,可以对任何XML模式进行操作(作为请求参数传入)。除了crud之外,它还可以创建和删除表,将内容导出到csv并导入csv文件。我所要做的就是在我的模式目录中删除一个新的模式文件,并为这个新表提供完整的CRUD。如果字段是FK,则在插入或更新时,输入框旁边会自动出现一个链接,单击该链接时,会弹出一个窗口以查找外键。如果字段是日期,则会自动显示弹出日历的链接。 我用JavaEE和JSP做了这个。但我相信也可以用PHP来完成。

    <schema>
      <tableName>xtblPersonnel</tableName>
      <tableTitle>Personnel</tableTitle>
      <tableConstraints></tableConstraints>
    <!-- COLUMNS ====================================== -->
    <column>
      <name>PID</name> 
      <type>VARCHAR2</type> 
      <size>9</size> 
      <label>Badge ID</label>
    </column> 
    <column>
      <name>PCLASS</name> 
      <type>VARCHAR2</type> 
      <size>329</size> 
      <label>Classification</label>
    </column> 
    <column>
      <name>PFOREMAN</name> 
      <type>VARCHAR2</type> 
      <size>9</size> 
      <label>Foreman Badge</label>
    </column> 
    <column>
      <name>REGDATE</name> 
      <type>DATE</type> 
      <size>10</size> 
      <label>Registration Date</label>
    </column> 
    <column>
      <name>PISEDITOR</name>
      <type>VARCHAR2</type> 
      <size>3</size> 
      <label>Is Editor?</label>
      <help>0=No</help>
      <help>1=Yes</help>
    </column> 
    <column>
      <name>PHOME</name> 
      <type>VARCHAR2</type> 
      <size>9</size> 
      <label>Home?</label>
    </column> 
    <column>
      <name>PNOTE</name>
      <type>VARCHAR2</type> 
      <size>35</size> 
      <label>Employee Notes</label>
    </column> 
    <!-- Primary Keys ====================================== -->
    <!-- The Primary Key type can be timestamp, enter, or a sequence name) -->
    <primaryKey>
      <name>PID</name>
      <type>enter</type>
    </primaryKey>  
    <!-- FOREIGN KEYS ====================================== -->
    <!-- The Foreign Key table is the lookup table using the Key to retreive the Label -->
    <foreignKey>
      <name>PID</name>
      <table>phonebook</table>
      <key>badge</key>
      <label>lname</label>
    </foreignKey>
    </schema>
    
        7
  •  0
  •   luiscolorado    16 年前

    好极了!你的想法很好,而且这个概念是正确的方向,而且已经由多家公司完成了。这是最初的“RAD”(快速应用程序开发)概念。

    其想法是将每个字段的属性保存在数据库中,也就是“元数据存储库”或“数据字典”。这不仅是一个好主意,而且是一个最佳实践,因此所有字段在类型、长度、描述等方面都是一致的。数据字典不仅应与用户界面一起使用,还应与数据库创建一起使用。更进一步,使用这种方法,您可以轻松地处理多个区域设置。

    不幸的是,现在RAD工具并不常见。它们是昂贵的,在某些情况下是不灵活和限制的。程序员喜欢编程,并且看不起这些工具。但是,谁知道呢?一个新的开源项目似乎每天都在启动!

    不幸的是,您的“工具集”非常有限,并且创建一个RAD工具并不是一项简单的任务:它涉及到一个意想不到的复杂程度。您可能需要学习.NET、Java或任何其他功能强大的语言。

    最好的方法是创建一个工具,该工具基于存储在数据库中的数据字典,生成ASP或任何需要的HTML,从而提高性能。如果字典或表单发生更改,只需运行生成器,就可以了!,您的新页面已准备就绪。

    如果需要,还需要允许“重写”字典。例如,在某些情况下,“电话”这个词对于某些形式来说太长了。此外,您还需要一个足够好的代码生成器,这样您就不必手动修改生成的代码,如果需要这样做,您的工具将足够聪明,能够记住这些更改。

    不幸的是,我帮不了你更多的忙。我的建议是:(1)提高你的技能;(2)寻找能够满足你需要的开源项目;(3)如果愿意,帮助项目;(4)让每个人都比其他人更快地进入产生灰尘的应用程序。;)

    推荐文章