I have two sets of data: "heat" and "cold", which are retrieved from another provider. This data is quite unorganized and I have removed lots of stuff in the code just to show the essential part of my problem. "Heat" and "cold" both contain properties that the user has to fill in. This property however is dynamic and the amount of properties is not fixed (hence it is in a loop as shown in the code).
My goal is to hide/disable the submit button, which is located all the way down, whenever one single input field in the list in either sets of data is empty. This should also preferably work on Internet Explorer 9, where the 'required' tag is not supported.
I have tried:
Adding the required tag. This unfortunately does not work in IE9 and I have some issues even in Google Chrome because it is still submitting my form. (I added the form tags too)
Adding Ng-show on the submit form. I checked whether the userInput is empty, but this still does not work.
Now you may ask, why wouldn't I just check in my controller whether these properties are empty in my submit method? While it is a good point, I can not access this dynamic data very easily in my controller. Hence, I need a solution that will hopefully fix this problem with no/mimimal effort in the controller.
Code:
<!--Start wrapper!-->
<div class="wrapper">
<div ng-repeat="(code, program) in data.old.heat">
<div class="row" ng-repeat="(componentId, component) in program">
<div class="inputForm">
<!--This field may not be left empty!-->
<input type="text" class="form" ng-model="component.userInput">
</div>
</div>
</div>
<div ng-repeat="(code, program) in data.old.cold">
<div class="row" ng-repeat="(componentId, component) in program">
<div class="inputForm">
<!--This field may not be left empty!-->
<input type="text" class="form" ng-model="component.userInput">
</div>
</div>
</div>
</div>
<!--End of wrapper !-->
<div class="submitPanel">
<button ng-click="submit()">Submit</button>
</div>
Here ya go : https://jsfiddle.net/DIRTY_SMITH/zxbe5rt0/
function validate(){
var text1 = document.getElementById('text').value;
if (text1.length > 0){
alert("went through");
return true;
}
alert("did not go through");
return false;
}
Not specific to angular, but you could check if it has characters via jQuery.
Html
<div class="submitPanel">
<button class="submit-btn" ng-click="submit()">Submit</button>
</div>
jQuery
$('#form input').blur(function()
{
if( $(this).val().length === 0 ) {
$(this).parents('.submit-btn').addClass('hide');
}
});
CSS
.hide{
display:none;
}
I have two options for you, but they both include ng-disabled (https://docs.angularjs.org/api/ng/directive/ngDisabled).
You can put this attribute on the button and you can either call a function on the scope in that attribute and check if all values are given.
So like: ng-disabled="checkInputs()".
Or
You wrap a form around all your inputs, give the form a name like name=form and set the required attribute on all inputs. (EDIT: you could use ng-required="true" for IE9.)
Then you could say ng-disabled="!form.$valid".
Related
I have multiple reason codes (For ex: RC1, RC2...). For each of these reason codes, I want to give the user a text box in which they can enter some comments. Also give them the option of adding multiple text boxes for each reason code.
To allow the user to add a dynamic text box, I have a button which allows the user to do so. If there was only one reason code, I can easily just just append a text box to the pre-existing text box using jquery (Using something like this: JQuery adding class to cloned element).
However since I have multiple reason codes(over 200) it doesnt make sense of having button for each reason code in Jquery. Is there a way for me to search by a basic identifier.
I have pasted the contents of the HTML file generated by my JSP file.
<div id="Reasoncode1">
<div id="inputTextBox_Reasoncode1">
<input type="text" placeholder="Add some text"/><button class="button_Reasoncode1">
+</button>
</div>
</div>
<p>
Reason code2
</p>
<div id="Reasoncode2">
<div id="inputTextBox_Reasoncode2">
<input type="text" placeholder="Add some text"/><button class="button_Reasoncode2">
+</button>
</div>
</div>
My Jquery attempt is:
$(".button_Reasoncode1").click(function() {
$('#Reasoncode1').clone().insertAfter('#inputTextBox_Reasoncode1');
});
$(".button_Reasoncode2").click(function() {
$('#Reasoncode2').clone().insertAfter('#inputTextBox_Reasoncode2');
});
I dont want to do this for each and every reason code, i was wondering if there is a better approach to this.
My JSFiddle: https://jsfiddle.net/mvp71L61/
Assuming all buttons are statically added to the DOM,
$("button[class*='button_Reasoncode']").click(function() {
var rCode = $(this).attr('class').match(/\d+/g)[0];
$("div[id='Reasoncode'+rcode]").clone().insertAfter("input[id='inputTextBox_Reasoncode'+rcode]");
});
I am working with jQuery 2.1.4 and javascript to do a simple Bootstrap form validation.
I found 3 strange things.
I am sure my jQuery code is working in the onblur and onfocus event of <input> elements (as you can try in my fiddle), but I cannot see .has-error class style. I have introduced boostrap.css etc. in my <head> part, of course.
<form-group> is indenting my paragraph to very end of left side of screen and it hides part of it, I must be using it wrongly but I don't know why.
Cancelar button is not working. I have tried <s:url value="/listaReservas.jsp" /> and plain url like in fiddle, no avail. FF complains about cancelar not defined.
Am I allowed to define a pure Javascript function like I did (mixing Javascript with jQuery), or I must bind it like this: $('#xxxId').click(function(){});???
Thanks all.
.has-error works but you need to make some changes. First, the class should be added to parent node form-group and second, your <input> field should have the class form-control. The HTML looks something like this:
<div class="form-group has-error">
<label class="control-label" for="tarjetaId">No. Tarjeta:</label>
<div class="controls">
<input class="input-xlarge form-control" id="tarjetaId" name="usuarioCompra.numeroTarjeta" value="" />
</div>
</div>
And the JavaScript
$("#tarjetaId").blur(function(){
var cuenta = $("#tarjetaId");
if (cuenta.val().length != 20){
cuenta.closest('.form-group').addClass("has-error");
$("#comprarButtonId").prop('disabled', true);
} else {
cuenta.closest('.form-group').removeClass("has-error");
}
});
As for .form-group giving your layout a negative margin. You are using .row as its parent, which also has negative margin. So you are actually applying two layers of negative margins. Having <div class="row"> is redundant.
Lastly, declare
function cancelar() {
window.location = "/listaReservas.jsp";
};
in the global scope, which means outside of $(document).ready(). The HTML for the submit button should have onclick="cancelar()" instead of onclick="cancelar"
I have a form with server-side validation. and if server returns validation errors I want to show them in the form, but only until user edited anything.
Ideally I want to have something like:
<form name='MyForm' ng-submit='doSomething()'>
<label for='my-field-id'>Some field</label>
<input type='text' id='my_field_id' ng-model='myField' name='my_field'>
<div ng-show-if-changed='MyForm.my_field.serverSideError'
ng-show-until='MyForm.my_field.changed'>Error!</div>
</form>
How to achieve this behavior? I really want to avoid to put this logic in a controller, and want to come up with some smart reusable directive.
UPDATE
Main thing here is how to implement ng-show-until-changed functionality. The logic of it must be "if an element is shown and target is changed - hide it". And the questions here:
if target will be just some scope variable, like MyForm.my_field.serverSideError - will I need to manually launch $digest when it may be changed? For example after AJAX request will be completed, and so probably some errors can arrive from the server? How to properly watch for these server-side errors changes ?
What is a proper way to hide/show some element in a custom directive in a same way as ng-show directive does that? is there some built-in utilites for that?
The simplest and crudest way is to add a text-box to the form, and make it read-only so the user can't do anything with it. But you can still use JavaScript to put text into the box, such as the error message you get from the server. And of course you can erase the text any time (triggered by, say, an onkeydown event-handler for the data-entry-field that the user edits).
A similar and more elegant way involves a <p> element in the HTML of your form, located near the place where you expect the user to do some editing:
<p id="errmsg"> </p>
In your Javascript you would do something like this, to prepare:
var P=document.getElementById("errmsg");
and then, when you need to display an error message from the server:
P.innerHTML="Text of error message";
and when the user begins editing (again, detect with an onkeydown event handler), you can replace the error-message text with another
If you really want to do hide/show of error messages, you might consider constructing several paragraphs, all with the same number of lines. Each would contain a pre-written error message, although one of them might be instructions regarding data that is supposed to be entered. That's the one to show by-default. All the paragraphs can be stacked up in the same place on the form, this way:
<div style="position:relative;">
<p id="p1" style="position:absolute;top='0px';left='0px';" hidden="">paragraph 1 text</p>
<p id="p2" style="position:absolute;top='0px';left='0px';" hidden="hidden">paragraph 2</p>
<p id="p3" style="position:absolute;top='0px';left='0px';" hidden="hidden">paragraph 3</p>
</div>
<br /> <!-- you will discover that some line-breaks are needed here -->
<br />
You would again use JavaScript to getElementById() of each paragraph, perhaps into an array of P[] variables. Then you can hide or display any of the paragraphs with
P[x].hidden="hidden";
P[x].hidden="";
You can hide the error message when the model changes and show it again when errors occure on submit.
See sample below or in this [plunker][1]
<!DOCTYPE html>
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
</head>
<body ng-app="changeExample">
<!-- snippet adapted from https://docs.angularjs.org/api/ng/directive/ngChange. -->
<script>
angular.module('changeExample', [])
.controller('ExampleController', [
'$scope',
function($scope) {
var model;
function simulateError(model) {
model.hasError = true;
model.errorMessage = "Some validation error!"
}
$scope.model = model = {
myField: 'my field value',
hasError: false,
errorMessage: '',
changed: false
};
$scope.change = function() {
model.hasError = false; // soon as the model changes unset the error.
};
$scope.doSomething = simulateError;
}
]);
</script>
<!--
snippet adapted from SO question
NOTES:
- using ng-change to listen to input field changes
- ng-trim="false" to listen to whitespace e.g spacebar
- hide error when user uses text input field
-->
<form name="myForm" ng-controller="ExampleController" ng-submit="doSomething(model)">
<label for="my-field-id">Fill in:</label>
<input type="text" id="my_field_id" ng-model="model.myField" ng-change="change()" ng-trim="false" />
<input type="submit" />
<div ng-show="model.hasError" ng-bind="model.errorMessage">
Error from server goes here!
</div>
</form>
</body>
</html>
[1]: http://plnkr.co/edit/BNBgiT?p=preview
This is an AngularJS application (1.2.16). I browse to a dialog to edit some item. One of the controls is a multi-SELECT with the following visible values:
incident
work order
These visible values correspond to the following data values:
INCIDENT
WORK_ORDER
This is done through using the ng-options=" ... as ... for ... in ... " pattern, using an enumeration:
var FlexFieldSubjectTypeEnum = {
INCIDENT:{name:"INCIDENT", description:"incident"},
WORK_ORDER:{name:"WORK_ORDER", description:"work order"}
}
If have a form pretty much as follows:
<form ng-submit="save(formName)" name="formName" class="form-horizontal">
...
<div class="control-group">
<label class="control-label">Subject type:</label>
<div class="controls">
<select name="subjectType"
ng-options="type.name as type.description for type in getEnumAsArray('FlexFieldSubjectTypeEnum') | orderBy:'name'"
ng-model="entity.subjectType"
required></select>
</div>
</div>
Now, if the dialog loads the item ($scope.entity) from the backend and entity.subjectType is set to the first item in the list, the form validation marks it as unset. I have many other dialogs with similar constructs and have not seen this problem anywhere else.
If the item returned from the backend points to the second item (WORK_ORDER), this is nicely represented in the SELECT ("work order") and there is no validation error.
The problem does exist equally when using required or ng-required="true".
The problem does not exist if I remove the required attribute, but then the field also suddenly becomes optional, which is not what I wanted.
Your help much appreciated!
Almost a month later, with meanwhile an upgrade from Bootstrap v2.2.2 to v3.1.1 the problem disappeared.
I am using jQuery and bootstrap to give drop-down search suggestions.Following is the html code.But when I type something in the search form and then clear the form.Two forms apears as in the picture.Why? I am new to jQuery. Thanks for any help.
<div class="container">
<div class="row">
<div class="span6 offset3">
<form class="form-search">
<input type="text" id="month" name="month" class="input-medium search-query">
<button type="submit" class="btn">Search</button>
<div id="suggestions">
</div>
</form>
</div>
</div>
</div>
<script>
jQuery("#month").keyup(function(){
ajax('search', ['month'], 'suggestions')});
</script>
EDIT:
I am using web2py framwork.This is the search function's code:
def search():
if not request.vars.month: return dict()
month_start = request.vars.month
selected=complete('piracyfinder',month_start) #this line get the search results
return DIV(*[DIV(k['title'],
_onclick="jQuery('#month').val('%s')" % k['title'],
_onmouseover="this.style.backgroundColor='lightblue'",
_onmouseout="this.style.backgroundColor='white'"
) for k in selected])
It appears you are using the same function (i.e., search()) to fill in the suggestions as well as to create the form (though that function doesn't process the form when submitted). According to the logic, when request.vars.month is either empty or does not exist, the function returns an empty dict. This will result in the associated view (i.e., /views/[controller name]/search.html) being executed and returned. Presumably the search.html view contains the HTML code shown above. So, when you clear the input box, the keyup handler is triggered and sends an empty month variable, which results in a new copy of the form being sent back and inserted in the "suggestions" div. You can avoid this problem by checking whether request.vars.month exists:
if not request.vars.month:
return '' if 'month' in request.vars else dict()
A better approach might simply be to use different functions for the search form and the suggestions given that they do completely different things and don't share any code.
if not request.vars.month also applies to the month var existing but being empty. Therefore, it's returning the form.
You need to do one of these:
Have your "suggestions" code be in a different page/file
Add a isAJAX variable to the request (or some other way to identify AJAX requests)
Check if the variable exists, rather than checking if it is falsy.