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
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 was wondering what is the proper way of store in html content that is displayed dynamically.
My case is that depending on what is clicked some sort of text is displayed in another part of a website. My first idea was to create a variable in js/jquery script to store this content so the script can access it whenever it is necessary.
this is an example:
var someContent=" Content to be displayed when something is clicked";
var a=$('#myid');
a.click(function(){
$('#myOtherId').text(someContent);
});
But after a while it came to my mind that the content should be stored in the html with a display value set to 'none' and js script should simple toggle its visibility depending wether it has been clicked or not.
Storing the content in js script seems much easier - but something tells me that there is better way to do it...
Indeed, you can do it by having the text in an HTML element, and use either jQuery's .toggle or .show depending on how you want it to respond to a second click:
$("#toggle").click(function () {
$('#msg').toggle(); // or .show() to have it in one way only
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="msg" style="display:none">Content to be displayed when something is clicked</span>
<br>
<button id="toggle">click me</button>
When the content is static, it seems more natural to have it embedded in your HTML, while when the content is dynamic (i.e. it depends on the actual state of the application), you would inject the dynamic part of the text with JavaScript.
For a non-JS-programmer in the development team (but with knowledge of HTML) it would in theory be easier to manipulate the messages when they are embedded in the HTML part of the page.
But this is a matter of opinion really.
Here is a mix of the two:
$("#enter").click(function () {
// Copy the number into the error message
$('#num').text($("#inp").val());
// Show the error message when the number is not even
$('#msg').toggle($('#inp').val() % 2 !== 0);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Enter an even number: <input id="inp" type="number" value=1>
<button id="enter">Verify</button>
<div id="msg" style="display:none; color:red">
The number <span id="num"></span> is not even
</div>
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".
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.
Im trying to make a contact form where people will check either "one way" ticket or "roundtrip".
The first "one way" is checked when user reach the contact form and one(1) date field is shown, but if "roundtrip" is checked i want a 2nd date field to be shown with a return date.
Any ideas?
Simply observe the onchange event for the radio button. When it reaches you can check weather single trip or round trip is selected and then show / hide the div with the return date fields.
<!DOCTYPE html>
<head>
<script>
function hdl_change(e) {
document.getElementById('date2').style.visibility =
e.checked && e.id == 'opt_2' ? 'visible' : 'hidden';
}
</script>
</head>
<body>
<form name="myForm">
<input id="opt_1" type="radio" name="trip" value="oneway" onchange="hdl_change(this)"> One way<br>
<input id="opt_2" type="radio" name="trip" value="round" onchange="hdl_change(this)"> Roundtrip<br>
</form>
<div id="date1"> date 1 stuff ...</div>
<div id="date2" style="visibility:hidden"> date 2 stuff ...</div>
</body>
</html>
You would need to use javascript and on-event handlers to accomplish that, as such dependent/binding functionality doesn't come with the regular html form elements (To avoid confusion: same goes for it's potential children).
This answer will give you a pretty good hint how to do it as it answers a question related to a similar problem/request: https://stackoverflow.com/a/5137316/1093284
Update:
As you don't seem very experienced, here's a most simplistic example:
<!-- include jquery.js library first (http://jquery.com/) -->
<script src="jquery.js"></script>
<!-- then work the magic -->
<script>
$(document).ready(function(){
$('#inputB').hide;
$('#checkboxA').click(
function(e){
$('#inputA').show;
$('#inputB').hide;
});
$('#checkboxB').click(
function(e){
$('#inputB').show;
$('#inputA').hide;
});
});
</script>
And if you're fit enough to go pro with jQuery, check the other answer here on this page at https://stackoverflow.com/a/11743381/1093284
Last but not least, I think the answer here at https://stackoverflow.com/a/11743482/1093284 provides the best solution, as it's small and does not require a full-blown 32kb javascript library. On the other hand, inline javascript is actually a no-go. Whatever... it's the users that count and they will prefer a quicker-loading page over nicely coded stuff behind the curtains.