-
Notifications
You must be signed in to change notification settings - Fork 358
Forms (Angular)
This describes an old version of forms, for current forms, go to Forms. For other kinds of forms, go to Forms (kinds)
(TODO: similar style to the rest) (currently just taken from https://github.com/ManageIQ/guides/pull/267)
- (all the changes from ruby TODO)
- uses $scope
- oftern still actually submits the form the old way
- TODO
TODO
def foo_new
assert_privileges('foo_new')
@record = Model.new
@in_a_form = true
replace_right_cell
end
def foo_edit
assert_privileges('foo_edit')
@record = find_record_with_rbac(Model, from_cid(params[:id]))
@in_a_form = true
replace_right_cell
end
def foo_create
assert_privileges('foo_new')
@record = Model.new
create_update
end
def foo_update
assert_privileges('foo_edit')
@record = find_record_with_rbac(Model, from_cid(params[:id]))
create_update
end
def create_update
TODO this changes
case params[:button]
when 'cancel'
javascript_redirect(:action => 'show_list',
:flash_msg => _("Add of new %{model} was cancelled by the user"))
when 'add', 'save'
set_record_vars
if @record.valid && @record.save
add_flash(_('Saved'))
@edit = nil
replace_right_cell
else
TODO flash co
javascript_flash
end
end
def set_record_vars
@record[:name] = params[:name] if params.key?(:name)
@record[:choice] = params[:choice] if params.key?(:choice)
end
TODO
ManageIQ.angular.app.controller('hostFormController', ['$http', '$scope', '$attrs', 'hostFormId', 'miqService', function($http, $scope, $attrs, hostFormId, miqService) {
var init = function() {
$scope.hostModel = {
name: '',
hostname: '',
ipmi_address: '',
custom_1: '',
user_assigned_os: '',
operating_system: false,
mac_address: '',
default_userid: '',
default_password: '',
remote_userid: '',
remote_password: '',
ws_userid: '',
ws_password: '',
ipmi_userid: '',
ipmi_password: '',
validate_id: '',
};
$scope.modelCopy = angular.copy( $scope.hostModel );
$scope.afterGet = false;
$scope.formId = hostFormId;
$scope.validateClicked = miqService.validateWithAjax;
$scope.formFieldsUrl = $attrs.formFieldsUrl;
$scope.createUrl = $attrs.createUrl;
$scope.updateUrl = $attrs.updateUrl;
$scope.model = "hostModel";
ManageIQ.angular.scope = $scope;
if (hostFormId == 'new') {
$scope.newRecord = true;
$scope.hostModel.name = "";
$scope.hostModel.hostname = "";
$scope.hostModel.ipmi_address = "";
$scope.hostModel.custom_1 = "";
$scope.hostModel.user_assigned_os = "";
$scope.hostModel.operating_system = false;
$scope.hostModel.mac_address = "";
$scope.hostModel.default_userid = "";
$scope.hostModel.default_password = "";
$scope.hostModel.remote_userid = "";
$scope.hostModel.remote_password = "";
$scope.hostModel.ws_userid = "";
$scope.hostModel.ws_password = "";
$scope.hostModel.ipmi_userid = "";
$scope.hostModel.ipmi_password = "";
$scope.hostModel.validate_id = "";
$scope.afterGet = true;
} else if (hostFormId.split(",").length == 1) {
miqService.sparkleOn();
$http.get($scope.formFieldsUrl + hostFormId)
.then(getHostFormDataComplete)
.catch(miqService.handleFailure);
} else if (hostFormId.split(",").length > 1) {
$scope.afterGet = true;
}
$scope.currentTab = "default";
};
$scope.changeAuthTab = function(id) {
$scope.currentTab = id;
}
$scope.addClicked = function() {
miqService.sparkleOn();
var url = 'create/new' + '?button=add';
miqService.miqAjaxButton(url, true);
};
$scope.cancelClicked = function() {
miqService.sparkleOn();
if (hostFormId == 'new') {
var url = $scope.createUrl + 'new?button=cancel';
} else if (hostFormId.split(",").length == 1) {
var url = $scope.updateUrl + hostFormId + '?button=cancel';
} else if (hostFormId.split(",").length > 1) {
var url = $scope.updateUrl + '?button=cancel';
}
miqService.miqAjaxButton(url);
};
$scope.saveClicked = function() {
miqService.sparkleOn();
if (hostFormId.split(",").length > 1) {
var url = $scope.updateUrl + '?button=save';
} else {
var url = $scope.updateUrl + hostFormId + '?button=save';
}
miqService.miqAjaxButton(url, true);
};
$scope.resetClicked = function() {
$scope.$broadcast ('resetClicked');
$scope.hostModel = angular.copy( $scope.modelCopy );
$scope.angularForm.$setUntouched(true);
$scope.angularForm.$setPristine(true);
miqService.miqFlash("warn", __("All changes have been reset"));
};
$scope.isBasicInfoValid = function() {
if(($scope.currentTab == "default") &&
($scope.hostModel.hostname || $scope.hostModel.validate_id) &&
($scope.hostModel.default_userid != '' && $scope.angularForm.default_userid.$valid &&
$scope.angularForm.default_password.$valid)) {
return true;
} else if(($scope.currentTab == "remote") &&
($scope.hostModel.hostname || $scope.hostModel.validate_id) &&
($scope.hostModel.remote_userid != '' && $scope.angularForm.remote_userid.$valid &&
$scope.angularForm.remote_password.$valid)) {
return true;
} else if(($scope.currentTab == "ws") &&
($scope.hostModel.hostname || $scope.hostModel.validate_id) &&
($scope.hostModel.ws_userid != '' && $scope.angularForm.ws_userid.$valid &&
$scope.angularForm.ws_password.$valid)) {
return true;
} else if(($scope.currentTab == "ipmi") &&
($scope.hostModel.ipmi_address) &&
($scope.hostModel.ipmi_userid != '' && $scope.angularForm.ipmi_userid.$valid &&
$scope.angularForm.ipmi_password.$valid)) {
return true;
} else
return false;
};
$scope.canValidate = function () {
if ($scope.isBasicInfoValid() && $scope.validateFieldsDirty())
return true;
else
return false;
}
$scope.canValidateBasicInfo = function () {
if ($scope.isBasicInfoValid())
return true;
else
return false;
}
$scope.validateFieldsDirty = function () {
if(($scope.currentTab == "default") &&
(($scope.angularForm.hostname.$dirty || $scope.angularForm.validate_id.$dirty) &&
$scope.angularForm.default_userid.$dirty &&
$scope.angularForm.default_password.$dirty)) {
return true;
} else if(($scope.currentTab == "remote") &&
(($scope.angularForm.hostname.$dirty || $scope.angularForm.validate_id.$dirty) &&
$scope.angularForm.remote_userid.$dirty &&
$scope.angularForm.remote_password.$dirty)) {
return true;
} else if(($scope.currentTab == "ws") &&
(($scope.angularForm.hostname.$dirty || $scope.angularForm.validate_id.$dirty) &&
$scope.angularForm.ws_userid.$dirty &&
$scope.angularForm.ws_password.$dirty)) {
return true;
} else if(($scope.currentTab == "ipmi") &&
($scope.angularForm.ipmi_address.$dirty &&
$scope.angularForm.ipmi_userid.$dirty &&
$scope.angularForm.ipmi_password.$dirty)) {
return true;
} else
return false;
}
function getHostFormDataComplete(response) {
var data = response.data;
$scope.hostModel.name = data.name;
$scope.hostModel.hostname = data.hostname;
$scope.hostModel.ipmi_address = data.ipmi_address;
$scope.hostModel.custom_1 = data.custom_1;
$scope.hostModel.user_assigned_os = data.user_assigned_os;
$scope.hostModel.operating_system = data.operating_system;
$scope.hostModel.mac_address = data.mac_address;
$scope.hostModel.default_userid = data.default_userid;
$scope.hostModel.remote_userid = data.remote_userid;
$scope.hostModel.ws_userid = data.ws_userid;
$scope.hostModel.ipmi_userid = data.ipmi_userid;
$scope.hostModel.validate_id = data.validate_id;
if ($scope.hostModel.default_userid !== '') {
$scope.hostModel.default_password = miqService.storedPasswordPlaceholder;
}
if ($scope.hostModel.remote_userid !== '') {
$scope.hostModel.remote_password = miqService.storedPasswordPlaceholder;
}
if ($scope.hostModel.ws_userid !== '') {
$scope.hostModel.ws_password = miqService.storedPasswordPlaceholder;
}
if ($scope.hostModel.ipmi_userid !== '') {
$scope.hostModel.ipmi_password = miqService.storedPasswordPlaceholder;
}
$scope.afterGet = true;
$scope.modelCopy = angular.copy( $scope.hostModel );
miqService.sparkleOff();
}
init();
}]);
- @angular_form = true
.form-horizontal
%form#form_div{"name" => "angularForm",
"ng-controller" => "hostFormController",
'ng-cloak' => '',
"ng-show" => "afterGet",
"novalidate" => true}
= render :partial => "layouts/flash_msg"
- if session[:host_items].nil?
%div
%div
.form-group{"ng-class" => "{'has-error': angularForm.name.$invalid}"}
%label.col-md-2.control-label{"for" => "name"}
= _("Name")
.col-md-8
%input.form-control{"type" => "text",
"id" => "name",
"name" => "name",
"ng-model" => "hostModel.name",
"maxlength" => "#{MAX_NAME_LEN}",
"miqrequired" => "",
"checkchange" => "",
"auto-focus" => ""}
%span.help-block{"ng-show" => "angularForm.name.$error.miqrequired"}
= _("Required")
.form-group{"ng-class" => "{'has-error': angularForm.hostname.$invalid}"}
%label.col-md-2.control-label{"for" => "hostname"}
= _("Hostname (or IPv4 or IPv6 address)")
.col-md-4
%input.form-control{"type" => "text",
"id" => "hostname",
"name" => "hostname",
"ng-model" => "hostModel.hostname",
"maxlength" => "#{MAX_HOSTNAME_LEN}",
"miqrequired" => "",
"checkchange" => ""}
%span.help-block{"ng-show" => "angularForm.hostname.$error.miqrequired"}
= _("Required")
.form-group{"ng-class" => "{'has-error': angularForm.user_assigned_os.$invalid}", "ng-hide" => "hostModel.operating_system"}
%label.col-md-2.control-label
= _("Host platform")
.col-md-8
= select_tag('user_assigned_os',
options_for_select([["<#{_('Choose')}>", nil]] + Host.host_create_os_types.to_a, disabled: ["<#{_('Choose')}>", nil]),
"ng-model" => "hostModel.user_assigned_os",
"checkchange" => "",
"ng-required" => "!hostModel.operating_system",
"selectpicker-for-select-tag" => "")
%span.help-block{"ng-show" => "angularForm.user_assigned_os.$error.required"}
= _("Required")
.form-group
%label.col-md-2.control-label
= _("Custom Identifier")
.col-md-8
%input#custom_1.form-control{"type" => "text",
"name" => "custom_1",
"ng-model" => "hostModel.custom_1",
"maxlength" => 50,
"checkchange" => ""}
.form-group{"ng-class" => "{'has-error': angularForm.ipmi_address.$error.requiredDependsOn}"}
%label.col-md-2.control-label{"for" => "ipmi_address"}
= _("IPMI IP Address")
.col-md-8
%input.form-control#ipmi_address{"type" => "text",
"id" => "ipmi_address",
"name" => "ipmi_address",
"ng-model" => "hostModel.ipmi_address",
"required-depends-on" => "hostModel.ipmi_userid",
"required-if-exists" => "ipmi_userid",
"maxlength" => 15,
"checkchange" => ""}
%span.help-block{"ng-show" => "angularForm.ipmi_address.$error.requiredDependsOn"}
= _("Required")
.form-group
%label.col-md-2.control-label
= _("MAC Address")
.col-md-8
%input#mac_address.form-control{"type" => "text",
"name" => "mac_address",
"ng-model" => "hostModel.mac_address",
"maxlength" => "#{MAX_NAME_LEN}",
"checkchange" => ""}
%hr
= render(:partial => "/layouts/angular/multi_auth_credentials",
:locals => {:record => @host, :ng_model => "hostModel"})
= render :partial => "layouts/angular/x_edit_buttons_angular"
- unless session[:host_items].nil?
%h3
= n_("Host", "Hosts", session[:host_items].length)
= _('Selected')
= _('Click on a Host to fetch its settings')
%table.admittable{:height => '75'}
%tbody
%tr
%td
- if session[:host_items]
- @embedded = true
- @gtl_type = settings(:views, :host)
= render :partial => 'layouts/gtl'
:javascript
ManageIQ.angular.app.value('hostFormId', '#{(@host.id || (session[:host_items] && session[:host_items].join(","))) || "new"}');
miq_bootstrap('#form_div');
%form#form_div{'name' => 'angularForm', '
= render :partial => "layouts/flash_msg"
%h3
= _("Foo")
.form-horizontal
.form-group
%label.col-md-2.control-label
= _('Name')
.col.md-8
= text_field_tag('name',
@edit[:new][:name],
:class => 'form-control',
'data-miq_observe' => {:url => url}.to_json)
.form-group
%label.col-md-2.control-label
= _('Choice')
.col.md-8
= select_tag('choice',
options_for_select([["<#{_('Choose')}>", nil]] + @choices),
"data-miq_sparkle_on" => true,
:class => "selectpicker")
:javascript
miqInitSelectPicker();
miqSelectPickerEvent('choice', '#{url}')
#dynamic_div
= render :partial => "dynamic"
%div{'ng-if' => 'choice == "foo"'}
= _("This could be a few more inputs")
%div{'ng-if' => 'choice == "bar"'}
= _("Or just a harmless message")
TODO
(from https://github.com/ManageIQ/manageiq-ui-classic/pull/1997#discussion_r140758135 :)
Working on the guide, but for now, pretty much all you need to do is:
rename init to $onInit - that gets called automagically by angular, so you no longer need to call it manually. move the templates under app/views/static/ - that way, you can reference it via templateUrl: '/static/....' from angular remove any controller-dependent logic from the moved template - that just means you can't use @record.id in your case make it into a component... ManageIQ.angular.app.controller("foo", controller); should become
ManageIQ.angular.app.component("foo", { bindings: { recordId: "@", } templateUrl: "/static/foo.html.haml", controller: controller, }); then you no longer need to pass the id using value, you can provide it to the component as a parameter - hence the bindings entry - so no injecting vmCloudRemoveSecurityGroupFormId any more ;) replace the original template with just something that uses the component .. so, %my-component{:record-id => @record.id}, and initializes angular (so that miq_bootstrap stays here, not in static - we usually use the component name as the first arg in those cases (so you don't need an extra #div)) don't leave the code in app/assets/javascripts/controllers, use the components dir for that - or if you're up to speed with the recent webpacker changes (talk), you can move it to app/javascript/ and use newer JS features. EDIT: oh, and remove ng-controller from the template too
Also, that miqAjaxButton is an anti-pattern now, with angular components, you should no longer rely on the server generating javascript to redirect you/show a flash message/whatever... instead, you should be using render :json => ... in ruby, and read that json in JS to do the right thing.
(But, it's not miqAjaxButton(url, true) which is the worst, so.. if the server-side logic to do that is not trivial, feel free to ignore this bit for now.)
( TODO all angular stages:
with $scope - angular pre-1.5, traditionally json, sometimes not and jquery controllerAs - clearer boundaries between controllers components - components, json, paramaters via component args )