You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by ma...@apache.org on 2015/05/15 07:22:04 UTC

[35/52] [abbrv] incubator-kylin git commit: add validation for data model

add validation for data model


Project: http://git-wip-us.apache.org/repos/asf/incubator-kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kylin/commit/3754d620
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kylin/tree/3754d620
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kylin/diff/3754d620

Branch: refs/heads/0.8.0
Commit: 3754d6201a7fd385042d739a5396c53a8f276632
Parents: 725598f
Author: jiazhong <ji...@ebay.com>
Authored: Mon Mar 30 19:46:58 2015 +0800
Committer: honma <ho...@ebay.com>
Committed: Fri May 15 11:36:53 2015 +0800

----------------------------------------------------------------------
 webapp/app/css/AdminLTE.css                     |  2 +-
 webapp/app/js/controllers/cubeModel.js          | 51 +++++++++++++++-
 webapp/app/js/controllers/modelSchema.js        | 62 +++++++++++++++++---
 webapp/app/js/model/tableModel.js               | 23 ++++++++
 webapp/app/less/app.less                        | 16 ++---
 webapp/app/less/component.less                  |  3 +
 webapp/app/partials/cubes/cube_detail.html      |  2 +-
 .../app/partials/modelDesigner/data_model.html  | 15 +++--
 .../modelDesigner/model_dimensions.html         | 53 +++++++++--------
 .../app/partials/modelDesigner/model_info.html  | 12 ++--
 webapp/app/partials/models/model_detail.html    |  2 +-
 webapp/app/partials/models/model_schema.html    |  9 ++-
 12 files changed, 185 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/css/AdminLTE.css
----------------------------------------------------------------------
diff --git a/webapp/app/css/AdminLTE.css b/webapp/app/css/AdminLTE.css
index 0b9307d..07b1c88 100644
--- a/webapp/app/css/AdminLTE.css
+++ b/webapp/app/css/AdminLTE.css
@@ -20,7 +20,7 @@ body {
 body {
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
-  font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+  /*font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;*/
   font-weight: 400;
   overflow-x: hidden;
   overflow-y: auto;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/js/controllers/cubeModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeModel.js b/webapp/app/js/controllers/cubeModel.js
index 2987905..1622370 100644
--- a/webapp/app/js/controllers/cubeModel.js
+++ b/webapp/app/js/controllers/cubeModel.js
@@ -18,7 +18,7 @@
 
 'use strict';
 
-KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaModel,SweetAlert,GraphService,$log) {
+KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaModel,SweetAlert,GraphService,$log,TableModel) {
 
 
     $scope.buildGraph = function (model) {
@@ -95,7 +95,8 @@ KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaMod
 
     // Controller for cube model lookup modal.
     var cubeModelLookupModalCtrl = function ($scope, $modalInstance) {
-        $scope.ok = function () {
+        $scope.ok = function (lookup_form) {
+            console.log(lookup_form);
             $modalInstance.close();
         };
 
@@ -176,4 +177,50 @@ KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaMod
         $scope.lookupState.editingIndex = -1;
         $scope.newLookup = Lookup();
     };
+
+    $scope.checkLookupForm = function(){
+            var errors = [];
+            // null validate
+            for(var i = 0;i<$scope.newLookup.join.primary_key.length;i++){
+                if($scope.newLookup.join.primary_key[i]==='null'){
+                    errors.push("Primary Key can't be null.");
+                    break;
+                }
+            }
+            for(var i = 0;i<$scope.newLookup.join.foreign_key.length;i++){
+                if($scope.newLookup.join.foreign_key[i]==='null'){
+                    errors.push("Foreign Key can't be null.");
+                    break;
+                }
+            }
+
+            //column type validate
+            var fact_table = $scope.model.fact_table;
+            var lookup_table = $scope.newLookup.table;
+
+            for(var i = 0;i<$scope.newLookup.join.primary_key.length;i++){
+                var pk_column = $scope.newLookup.join.primary_key[i];
+                var fk_column = $scope.newLookup.join.foreign_key[i];
+                if(pk_column!=='null'&&fk_column!=='null'){
+                    var pk_type = TableModel.getColumnType(pk_column,lookup_table);
+                    var fk_type = TableModel.getColumnType(fk_column,fact_table);
+                    if(pk_type!==fk_type){
+                        errors.push(" Column Type incompatible "+pk_column+"["+pk_type+"]"+","+fk_column+"["+fk_type+"].");
+                    }
+                }
+            }
+
+            var errorInfo = "";
+            angular.forEach(errors,function(item){
+                errorInfo+="\n"+item;
+            });
+            if(errors.length){
+//                SweetAlert.swal('Warning!', errorInfo, '');
+                SweetAlert.swal('', errorInfo, 'warning');
+                return false;
+            }else{
+                return true;
+            }
+
+    };
 });

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
index 4d7b6c1..883bb3a 100644
--- a/webapp/app/js/controllers/modelSchema.js
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -18,7 +18,7 @@
 
 'use strict';
 
-KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,$log) {
+KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,$log,SweetAlert) {
 
     $log.info($scope.model);
 
@@ -26,17 +26,17 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
     $scope.newDimension = null;
     $scope.newMeasure = null;
 
+    $scope.forms = {};
+
 
     $scope.wizardSteps = [
         {title: 'Model Info', src: 'partials/modelDesigner/model_info.html', isComplete: false,form:'model_info_form'},
-        {title: 'Data Model', src: 'partials/modelDesigner/data_model.html', isComplete: false,form:null},
-        {title: 'Dimensions', src: 'partials/modelDesigner/model_dimensions.html', isComplete: false,form:null},
+        {title: 'Data Model', src: 'partials/modelDesigner/data_model.html', isComplete: false,form:'data_model_form'},
+        {title: 'Dimensions', src: 'partials/modelDesigner/model_dimensions.html', isComplete: false,form:'model_dimensions'},
         {title: 'Measures', src: 'partials/modelDesigner/model_measures.html', isComplete: false,form:null},
         {title: 'Settings', src: 'partials/modelDesigner/conditions_settings.html', isComplete: false,form:null}
     ];
 
-    $scope.formStepMap =[{}]
-
     $scope.curStep = $scope.wizardSteps[0];
 
 
@@ -95,11 +95,55 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
         }
     };
 
-    $scope.goToStep = function(stepIndex,form){
-        if(form){
-            console.log($scope[form]);
-            console.log(document.querySelector("form"));
+    $scope.checkForm = function(){
+        if(!$scope.curStep.form){
+            return true;
+        }
+        if($scope.state.mode==='view'){
+            return true;
+        }
+        else{
+            //form validation
+            if($scope.forms[$scope.curStep.form].$invalid){
+                return false;
+            }else{
+                //business rule check
+                switch($scope.curStep.form){
+                    case 'data_model_form':
+                        return $scope.check_data_model();
+                     break;
+                    default:
+                        return true;
+                        break;
+                }
+            }
         }
+    };
+
+    /*
+     * lookups can't be null
+     */
+    $scope.check_data_model = function(){
+        var errors = [];
+        if(!$scope.model.lookups.length){
+            errors.push("No lookup table defined");
+        }
+        var errorInfo = "";
+        angular.forEach(errors,function(item){
+            errorInfo+="\n"+item;
+        });
+        if(errors.length){
+            SweetAlert.swal('', errorInfo, 'warning');
+            return false;
+        }else{
+            return true;
+        }
+
+    }
+
+
+
+    $scope.goToStep = function(stepIndex){
         for(var i=0;i<$scope.wizardSteps.length;i++){
             if(i<=stepIndex){
                 $scope.wizardSteps[i].isComplete = true;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/js/model/tableModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/tableModel.js b/webapp/app/js/model/tableModel.js
index f482909..55b4e7b 100755
--- a/webapp/app/js/model/tableModel.js
+++ b/webapp/app/js/model/tableModel.js
@@ -138,6 +138,29 @@ KylinApp.service('TableModel', function(ProjectModel,$q,TableService,$log) {
 
         return defer.promise;
     };
+
+    this.getColumnType = function(_column,_table){
+        var columns = _this.getColumnsByTable(_table);
+        var type;
+        angular.forEach(columns,function(column){
+            if(_column === column.name){
+                type = column.datatype;
+                return;
+            }
+        });
+        return type;
+    };
+
+    this.getColumnsByTable = function (tableName) {
+        var temp = [];
+        angular.forEach(_this.selectProjectTables, function (table) {
+            if (table.name == tableName) {
+                temp = table.columns;
+            }
+        });
+        return temp;
+    };
+
     this.innerSort =function(a, b) {
         var nameA = a.name.toLowerCase(), nameB = b.name.toLowerCase();
         if (nameA < nameB) //sort string ascending

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/less/app.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/app.less b/webapp/app/less/app.less
index 9c629d0..8763bb7 100644
--- a/webapp/app/less/app.less
+++ b/webapp/app/less/app.less
@@ -364,14 +364,14 @@ pre {
   background: url("../image/icon_table.png") no-repeat;
 }
 
-input.ng-invalid-required {
-  border: 1px solid #dd4b39;
-}
-
-input.ng-invalid-required:after {
-  content: "*";
-  color: red;
-}
+//input.ng-invalid-required {
+//  border: 1px solid #dd4b39;
+//}
+//
+//input.ng-invalid-required:after {
+//  content: "*";
+//  color: red;
+//}
 
 .nav-pills>li {
 cursor: pointer;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/less/component.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/component.less b/webapp/app/less/component.less
index ee28e84..14a6fe8 100644
--- a/webapp/app/less/component.less
+++ b/webapp/app/less/component.less
@@ -968,4 +968,7 @@ Angular 1.2.0 Animation
 //form validate
 .has-feedback{
 
+}
+.highlight-bule{
+  color:#428bca !important;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/cubes/cube_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubes/cube_detail.html b/webapp/app/partials/cubes/cube_detail.html
index f5652eb..93084e3 100755
--- a/webapp/app/partials/cubes/cube_detail.html
+++ b/webapp/app/partials/cubes/cube_detail.html
@@ -47,7 +47,7 @@
             <a href="" ng-click="cube.visiblePage='hbase';getHbaseInfo(cube)">HBase</a>
         </li>
         <li class="dropdown" ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission(cube, permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, permissions.OPERATION.mask)">
-            <a class="dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="true">
+            <a class="dropdown-toggle highlight-bule" data-toggle="dropdown" href="#" aria-expanded="true">
                 <i class="fa fa-cubes">Action</i> <span class="caret"></span>
             </a>
             <ul class="dropdown-menu">

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/modelDesigner/data_model.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/data_model.html b/webapp/app/partials/modelDesigner/data_model.html
index c8cc5a7..79c6533 100644
--- a/webapp/app/partials/modelDesigner/data_model.html
+++ b/webapp/app/partials/modelDesigner/data_model.html
@@ -17,7 +17,7 @@
 -->
 
 <div ng-controller="CubeModelCtrl">
-    <ng-form name="model_form">
+    <ng-form name="forms.data_model_form">
 
     <!-- Fact Table Name -->
     <div class="form-group">
@@ -25,9 +25,11 @@
             <label class="col-xs-12 col-sm-2 concube.detailtrol-label no-padding-right font-color-default">
                 <b>Fact Table</b>
             </label>
-            <div class="col-xs-12 col-sm-6">
+            <div class="col-xs-12 col-sm-6" ng-class="forms.data_model_form.innerform.typeahead.$invalid?'has-error':''">
                 <typeahead ng-if="state.mode=='edit'" items="tableModel.selectProjectTables" prompt="Fact Table Name"
                            title="name" model="model.fact_table" required="true"></typeahead>
+                <small class="help-block" ng-show="forms.data_model_form.innerform.typeahead.$error.required">The fact table is required</small>
+
                 <span ng-if="state.mode=='view'">{{model.fact_table}}</span>
             </div>
         </div>
@@ -109,12 +111,13 @@
                 <div class="col-xs-8">
                     <ng-form name="lookup_form">
                     <!--Table Name-->
-                    <div class="form-group">
+                    <div class="form-group" ng-class="lookup_form.innerform.typeahead.$invalid?'has-error':''">
                         <div class="row">
                             <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Lookup Table Name</b></label>
                             <div class="col-xs-12 col-sm-6">
-                                <typeahead items="tableModel.selectProjectTables" prompt="Lookup Table Name" title="name" model="newLookup.table"></typeahead>
+                                <typeahead items="tableModel.selectProjectTables" prompt="Lookup Table Name" required="true" title="name" model="newLookup.table"></typeahead>
                             </div>
+                            <small class="help-block" ng-show="lookup_form.innerform.typeahead.$error.required">Table name required</small>
                         </div>
                     </div>
 
@@ -123,7 +126,7 @@
                         <div class="row">
                             <label class="col-sm-3 control-label font-color-default"><b>Join Type</b></label>
                             <div class="col-sm-6">
-                                <select class="form-control" chosen ng-model="newLookup.join.type"
+                                <select class="form-control"  chosen ng-model="newLookup.join.type"
                                         ng-options="joinType.value as joinType.name for joinType in cubeConfig.joinTypes">
                                     <option value=""></option>
                                 </select>
@@ -192,7 +195,7 @@
             </div>
         </div>
         <div class="modal-footer">
-            <button class="btn btn-primary" ng-disabled="lookup_form.$invalid || !newLookup.join.primary_key.length" ng-click="ok()">OK</button>
+            <button class="btn btn-primary" ng-disabled="lookup_form.$invalid || !newLookup.join.primary_key.length" ng-click="checkLookupForm()?ok():''">OK</button>
             <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
         </div>
     </script>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/modelDesigner/model_dimensions.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_dimensions.html b/webapp/app/partials/modelDesigner/model_dimensions.html
index 62af873..10a8d77 100644
--- a/webapp/app/partials/modelDesigner/model_dimensions.html
+++ b/webapp/app/partials/modelDesigner/model_dimensions.html
@@ -32,33 +32,34 @@
         </div>
     </div>
 
+    <ng-form name="model_dimensions" novalidate>
      <!-- VIEW MODE -->
-    <table class="table table-striped table-hover" ng-if="state.mode=='view'&&model.dimensions.length > 0">
-        <thead>
-            <tr>
-                <th>ID</th>
-                <th>Table Name</th>
-                <th>Columns</th>
-            </tr>
-        </thead>
-        <tbody class="cube-dimension">
-            <tr ng-repeat="dimension in model.dimensions | filter:dimState.filter track by $index">
-                <!--ID -->
-                <td>
-                    <b>{{dimension.id = ($index + 1)}}</b>
-                </td>
-                <!--Name -->
-                <td>
-                    <span>{{dimension.table}}</span>
-                </td>
-                <!--Table Name -->
-                <td>
-                    <span>{{dimension.columns}}</span>
-                </td>
-            </tr>
-        </tbody>
-    </table>
-
+        <table class="table table-striped table-hover" ng-if="state.mode=='view'&&model.dimensions.length > 0">
+            <thead>
+                <tr>
+                    <th>ID</th>
+                    <th>Table Name</th>
+                    <th>Columns</th>
+                </tr>
+            </thead>
+            <tbody class="cube-dimension">
+                <tr ng-repeat="dimension in model.dimensions | filter:dimState.filter track by $index">
+                    <!--ID -->
+                    <td>
+                        <b>{{dimension.id = ($index + 1)}}</b>
+                    </td>
+                    <!--Name -->
+                    <td>
+                        <span>{{dimension.table}}</span>
+                    </td>
+                    <!--Table Name -->
+                    <td>
+                        <span>{{dimension.columns}}</span>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </ng-form>
     <div  ng-if="state.mode=='edit'" class="form-group model-dimension-edit" style="width: 100%">
         <h4 style="margin-left:42px">Dimensions</h4>
         <table style="margin-left:42px; width:92%"

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/modelDesigner/model_info.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_info.html b/webapp/app/partials/modelDesigner/model_info.html
index ca7e231..21a8185 100644
--- a/webapp/app/partials/modelDesigner/model_info.html
+++ b/webapp/app/partials/modelDesigner/model_info.html
@@ -19,7 +19,7 @@
 <div class="row">
     <div class="col-xs-8">
         <!--Project-->
-        <ng-form name="model_info_form" novalidate>
+        <ng-form name="forms.model_info_form" novalidate>
             <div class="form-group">
                 <div class="row">
                     <label class="col-xs-3 control-label no-padding-right">
@@ -28,11 +28,11 @@
                         </a>
                         <b ng-if="state.mode=='view'" class="font-color-default">Project</b>
                     </label>
-                    <div class="col-xs-6" ng-class="model_info_form.project_name.$invalid?'has-error':model_info_form.project_name.$dirty?'has-success':''">
+                    <div class="col-xs-6" ng-class="forms.model_info_form.project_name.$invalid?'has-error':''">
                          <!--edit-->
                         <input ng-if="state.mode=='edit'" required name="project_name" type="text" class="form-control"
                                ng-model="model.project"/>
-                        <small class="help-block" ng-show="model_info_form.project_name.$error.required">The project is required</small>
+                        <small class="help-block" ng-show="forms.model_info_form.project_name.$error.required">The project is required</small>
 
                         <!--view-->
                         <span ng-if="state.mode=='view'">
@@ -49,15 +49,15 @@
                         <b>Model Name</b>
                     </label>
 
-                    <div class="col-xs-12 col-sm-6" ng-class="model_info_form.model_name.$invalid?'has-error':model_info_form.model_name.$dirty?'has-success':''">
+                    <div class="col-xs-12 col-sm-6" ng-class="forms.model_info_form.model_name.$invalid?'has-error':''">
 
                         <!-- edit -->
                         <input ng-if="state.mode=='edit'" name="model_name" type="text" class="form-control"
                                ng-model="model.name" required
                                placeholder="You can use letters, numbers, and '_'"
                                ng-maxlength=100 ng-pattern="/^\w+$/" />
-                        <small class="help-block" ng-show="model_info_form.model_name.$error.required  && model_info_form.model_name.$dirty">Model name is required.</small>
-                        <small class="help-block" ng-show="model_info_form.model_name.$invalid && model_info_form.model_name.$dirty && !model_info_form.model_name.$error.required"> Model name is invalid.</small>
+                        <small class="help-block" ng-show="forms.model_info_form.model_name.$error.required  && forms.model_info_form.model_name.$dirty">Model name is required.</small>
+                        <small class="help-block" ng-show="forms.model_info_form.model_name.$invalid && forms.model_info_form.model_name.$dirty && !forms.model_info_form.model_name.$error.required"> Model name is invalid.</small>
 
 
                         <span ng-if="state.mode=='view'">{{model.name}}</span>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/models/model_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_detail.html b/webapp/app/partials/models/model_detail.html
index 1808d5e..e26c29f 100644
--- a/webapp/app/partials/models/model_detail.html
+++ b/webapp/app/partials/models/model_detail.html
@@ -30,7 +30,7 @@
             <a href="" ng-click="model.visiblePage='json_model';">JSON</a>
         </li>
         <li class="dropdown" ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission(model, permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, permissions.OPERATION.mask)">
-            <a class="dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="true">
+            <a class="dropdown-toggle highlight-bule" data-toggle="dropdown" href="#" aria-expanded="true">
                 <i class="fa fa-star"> Action </i> <span class="caret"></span>
             </a>
             <ul class="dropdown-menu">

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/models/model_schema.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_schema.html b/webapp/app/partials/models/model_schema.html
index ac607e6..86a3196 100644
--- a/webapp/app/partials/models/model_schema.html
+++ b/webapp/app/partials/models/model_schema.html
@@ -28,7 +28,7 @@
                 <ul class="wizard-steps">
                     <li ng-repeat="step in wizardSteps"
                         class="{{step==curStep?'active':''}} {{step.isComplete?'complete':''}}">
-                        <span style="cursor:pointer;" ng-click="goToStep($index,curStep.form)" class="step">{{step.step = ($index + 1)}}</span>
+                        <span style="cursor:pointer;" ng-click="checkForm()?goToStep($index):''" class="step">{{step.step = ($index + 1)}}</span>
                         <span class="title">{{step.title}}</span>
                      </li>
                 </ul>
@@ -40,18 +40,17 @@
             <hr/>
             <div class="wizard-actions">
                 <div class="row">
-                    <div class="col-xs-8" style="display:none;">
-                        <p style="color: #808080;text-align: left;"><b>Note:</b> inputs with <span style="color: lightblue">light blue</span> border are mandatory.</p>
+                    <div class="col-xs-8" style="display:block;">
                         <div>
                             <a href="models" class="pull-left"><i class="fa fa-arrow-left"></i> Back to My Models</a>
                         </div>
                     </div>
                     <div class="col-xs-4 pull-right">
-                        <button class="btn btn-prev" ng-click="preView()" ng-show="curStep.title!='Model Info'">
+                        <button class="btn btn-prev" ng-click="checkForm()?preView():''" ng-show="curStep.title!='Model Info'">
                             <i class="ace-icon fa fa-arrow-left"></i>
                             Prev
                         </button>
-                        <button id="nextButton" class="btn btn-success btn-next"  ng-click="nextView()" ng-disabled="design_form.$invalid"
+                        <button id="nextButton" class="btn btn-success btn-next"  ng-click="checkForm()?nextView():''" ng-disabled="design_form.$invalid"
                                 ng-show="curStep.title!='Settings'">
                             Next
                             <i class="ace-icon fa fa-arrow-right icon-on-right"></i>