diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 7771802bc98bd051261fac91c6dc92f4d7f27a6a..846202885125b7e1f9611f815f6ce2f236187d04 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -266,6 +266,20 @@ class DynamicFormField extends VerySimpleModel {
         return $this->get('edit_mask') & 8;
     }
 
+    /**
+     * Used when updating the form via the admin panel. This represents
+     * validation on the form field template, not data entered into a form
+     * field of a custom form. The latter would be isValidEntry()
+     */
+    function isValid() {
+        if (count($this->errors()) || !parent::isValid())
+            return false;
+        if ($this->get('required') && !$this->get('name'))
+            $this->addError(
+                "Variable name is required for required fields", "name");
+        return count($this->errors()) == 0;
+    }
+
     function delete() {
         // Don't really delete form fields as that will screw up the data
         // model. Instead, just drop the association with the form which
diff --git a/include/class.forms.php b/include/class.forms.php
index 8bfe89fc6e361b6824d2c463d3b514e876fb0026..97c27e922a28690605cfc9ffb4c1bfc82a2158ff 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -183,6 +183,12 @@ class FormField {
     function errors() {
         return $this->_errors;
     }
+    function addError($message, $field=false) {
+        if ($field)
+            $this->_errors[$field] = $message;
+        else
+            $this->_errors[] = $message;
+    }
 
     function isValidEntry() {
         $this->validateEntry();
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index b5f18b1411284bf260901077a9e2a987c7cde636..b7b9e875f03958b305ff2fe7ded27fe53fceede8 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -59,7 +59,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             <th>Type</th>
             <th>Internal</th>
             <th>Required</th>
-            <th>Name</th>
+            <th>Variable</th>
             <th>Delete</th>
         </tr>
     </thead>
@@ -95,12 +95,12 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             <th>Type</th>
             <th>Internal</th>
             <th>Required</th>
-            <th>Name</th>
+            <th>Variable</th>
             <th>Delete</th>
         </tr>
     </thead>
     <tbody class="sortable-rows" data-sort="sort-">
-    <?php if ($form) foreach ($form->getFields() as $f) {
+    <?php if ($form) foreach ($form->getDynamicFields() as $f) {
         $id = $f->get('id');
         $deletable = !$f->isDeletable() ? 'disabled="disabled"' : '';
         $force_name = $f->isNameForced() ? 'disabled="disabled"' : '';
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index 826d19e7962553244971c135af0c4ce5280c59bd..1b1ed786a72f46a2819f1c9641a1bd28eb4a9e57 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -18,8 +18,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     </thead>
     <tbody>
         <?php
-        $uf = UserForm::objects();
-        $uf[0]->render();
+        $uf = UserForm::getInstance();
+        $uf->render();
         if($cfg->notifyONNewStaffTicket()) {  ?>
         <tr>
             <td width="160">Alert:</td>
diff --git a/scp/forms.php b/scp/forms.php
index 5c0a2ad0481f53c013cc4cd509d778a91a0dd2ba..311207756652d6c1d560d79923a93bc16abc0c5b 100644
--- a/scp/forms.php
+++ b/scp/forms.php
@@ -40,9 +40,14 @@ if($_POST) {
                 }
                 if ($field->isValid())
                     $field->save();
+                else
+                    # notrans (not shown)
+                    $errors["field-$id"] = 'Field has validation errors';
                 // Keep track of the last sort number
                 $max_sort = max($max_sort, $field->get('sort'));
             }
+            if ($errors)
+                $errors['err'] = 'Unable to commit form. Check validation errors';
             break;
         case 'add':
             $form = DynamicForm::create(array(
@@ -94,7 +99,8 @@ if($_POST) {
                 $field->save();
         }
         // XXX: Move to an instrumented list that can handle this better
-        $form->_dfields = $form->_fields = null;
+        if (!$errors)
+            $form->_dfields = $form->_fields = null;
     }
 }
 
diff --git a/scp/js/scp.js b/scp/js/scp.js
index 83bc37a4cf99cec90afc366a64bcecbda48328f2..2cfcc10284c979dc8c3c44ddc82e43289989f939 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -115,8 +115,8 @@ $(document).ready(function(){
         });
     }
 
-    $("form#save :input").change(function() {
-        var fObj = $(this).closest('form');
+    var warnOnLeave = function (el) {
+        var fObj = el.closest('form');
         if(!fObj.data('changed')){
             fObj.data('changed', true);
             $('input[type=submit]', fObj).css('color', 'red');
@@ -124,6 +124,10 @@ $(document).ready(function(){
                 return 'Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!';
              });
         }
+    };
+
+    $("form#save :input").change(function() {
+        warnOnLeave($(this));
     });
 
     $("form#save :input[type=reset]").click(function() {
@@ -453,6 +457,7 @@ $(document).ready(function(){
        'helper': fixHelper,
        'stop': function(e, ui) {
            var attr = ui.item.parent('tbody').data('sort');
+           warnOnLeave(ui.item);
            $('input[name^='+attr+']', ui.item.parent('tbody')).each(function(i, el) {
                $(el).val(i+1);
            });