Clear input field - javascript

I'm trying to clear ng-model inputs, but is not working, and i can't figure out why.
I have:
<button ng-click="$ctrl.clear()"></button>
and in the clear action i have:
$scope.$event = null;
Should work, right?
If i do:
<button ng-click="$event = null"></button>
Will work, but i want avoid this in the HTML.
I already try to use angular.copy, and:
$scope.$event = {};
$scope.$event = '';
But doesn't work and is not giving me any erros message.
Thanks.
UPDATE:
<input type="text" ng-model="$event.title"/>
<input type="text" ng-model="$event.name"/>
<input type="number" ng-model="$event.age"/>
<input type="date" ng-model="$event.date"/>

The problem is in the click handler, $event refers to the event object not your event object in the scope.
Use another name to refer your object. Note that property names starting with $ is normally used by angularjs to refer to its properties, so best we don't use them.

Related

How do I get same result using addEventListener (keyup) instead of onkeyup attribute in the HTML?

I want to restrict an input text through a regular expression. In the first example I use the attribute onkeyup = "lettersOnly(this)" inside the HTML, as follows:
<form>
<label for="username">Choose a Username:</label>
<input type="text" name="username" id="username" onkeyup="lettersOnly(this)">
</form>
<script>
function lettersOnly(input){
var regex = /[^a-z]/gi;
input.value = input.value.replace(regex, "");
}
</script>
It works but I learnt that this is a bad practice. I found other solution avoiding that, and setting someVariable.onkeyup inside <script> tags. However, my goal is to find another way to get the same result using addEventListener ('keyup', lettersOnly, false). I researched a lot for this specific situation but no answers. Is it possible? I tried the following:
<form>
<label for="username">Choose a Username:</label>
<input type="text" name="username" id="username">
<!--No more “onkeyup” attribute.-->
</form>
<script>
function lettersOnly(input){
var regex = /[^a-z]/gi;
input.value.addEventListener('keyup', lettersOnly(input){
input.value = input.value.replace(regex, "");
}, false)
}
</script>
Doesn‘t work. My intention is to avoid the event handler in the html and use instead, the addEventListener. What is wrong in this last coding? Why doesn‘t work? I‘ll really appreciate your patience.
In the code that you said you have tried; the function lettersOnly() will never be called and addEventListener() will never be called.
You can simply change it as follow -
<script>
function lettersOnly(input){
var regex = /[^a-z]/gi;
input.value = input.value.replace(regex, "");
}
document.getElementById("username").addEventListener("keyup", lettersOnly(this), false);
</script>
Finally, I found myself a solution and I want to share it.
<form>
<label for="username">Choose a Username:</label>
<input type="text" name="username" id="username">
<!--No more “onkeyup” attribute.-->
</form>
<script>
let user = document.getElementById("username");
var regex = /[^a-z]/gi;
user.addEventListener("keyup", ()=>{
user.value = user.value.replace(regex, "");
})
// The “user” variable has been just to simplify a lot of repeated coding, as it is equivalent to “document.getElementById(“username”).
</script>
I don‘t know if this is the best and optimal way to solve my inquire but it works. No “ONkeyup” at all, but using, instead, addEventListener ("keyup", anonymous arrow function). I‘ll really appreciate if anybody has any other suggestion.
The main problem with your second piece of code was that you weren't actually attaching the eventListener to the input element since the outer lettersOnly function was also not called at any time. It appears you resolved this in your own answer, but I'm going to expand upon my comment and suggest using keydown instead.
In the following snippet, I changed the eventListener to attach to keydown instead of keyup. Then we test if the new key (via event.key) matches our regex with .match. If the key pressed is a non-letter character, the match will be non-null, so we want to utilize event.preventDefault() to interrupt the new key from being added to the input value.
Note: this has the added benefit of not needing to use replace or replaceAll to remove the invalid character.
var regex = /[^a-z]/gi;
function lettersOnly(event) {
if (event.key.match(regex) !== null) {
// Since it is an invalid character, we will prevent default
event.preventDefault();
// Log the key to the console for demonstration
console.log(event.key);
// Not needed since we preventDefault()
//event.target.value = event.target.value.replace(regex, "");
}
}
// `username` is equivalent to `document.getElementById("username")
username.addEventListener("keydown", lettersOnly, false);
<form>
<label for="username">Choose a Username:</label>
<input type="text" name="username" id="username">
</form>

Form change and validity in angularjs

Whenever any non-readonly input in my form changes and the form is valid, I want to do certain action. Let's say, my form looks like
<form name="form" novalidate>
<input ng-model='input.a' required/>
<input ng-model='input.b' required/>
<input value='{{output.p | number: 2}}' readonly/>
<input value='{{output.q | number: 2}}' readonly/>
</form>
Now upon any change of input, I want to do something, whenever input.a and input.b are valid. I tried $watch(input), but it didn't work. Watching all its members does, but it feels stupid. Adding ng-change to all fields feels better, but still pretty stupid (non-DRY). What's the proper way?
The other question is how to find out if the input is valid. If I had a button, I could do simply
<button ng-click="doIt()" ng-disabled="form.$invalid">
but how can I access form.$invalid in the controller (it's not contained in $scope)?
You should be able to access form.$invalid by doing
$scope.form.$invalid
See here: AngularJs can't access form object in controller ($scope)
To watch for changes in the form, you should be able to do:
$scope.$watchCollection('input')
#dave has already answered your first question, but for the second I have a solution that I consider more elegant:
In your controller you have declare an object, for example:
$scope.forms = {};
Then you form name must be nested inside that object:
<form name="forms.someForm">
...
Finally in your controller you can do things like this:
if($scope.forms.someForm.$invalid) {
...
}

Check $pristine status of ngModel without using a form

Am trying to figure out how to check the state of a ngModel without using a form tag. I don't have wrappers is just basic input element with a ngModel.
All the examples I have found so far are for form validations and in this case, there is no form.
When i tried something like:
HTML
<input type="text" ng-model="lastname">
SCRIPT:
if($scope.lastname.$dirty) {
console.log('last name has changed');
}
I get undefined.
Is there a way to check the state of the ngModel without adding a watch directive to it? it seems it would be something basic that is part of the framework. Why wouldn't this work?
There are two ways:
1. Use ng-form:
<span ng-form="myForm">
<input type="text" name="name" ng-model="name" required/>
</span>
Now you can access the model either at $scope.myForm.namein your controller or with myForm.name in your view:
var isPristine = $scope.myForm.name.$pristine;
2. Use angular.element().controller('ngModel') (Don't do this one, bad bad bad)
Alternatively, you could hack your way around it. But this is going to be ugly, untestable, and gross:
var elem = angular.element(document.getElementById('myElement'));
var model = elem.controller('ngModel');
var isPristine = model.$pristine;
Edit: Your situation (per your comment) inside of a repeater
the only difference between my example and your is that the input field is inside a ng-repeater. Thought that wouldn't matter but I guess it does.
And now it's time to ask yourself what you're doing and why... You can still get the information you need using ng-form, but you'll need to do some crazy stuff I wouldn't recommend:
<div ng-repeater="item in items track by $index">
<span ng-form="rptrForm">
<input type="text" name="name" ng-model="item.name" required/>
</span>
</div>
.. commence craziness:
// get the first child scope (from the repeater)
var child = $scope.$$childHead;
while(child) {
var isPristine = child.rptrForm.$pristine;
var item = child.item;
if(!isPristine) {
// do something with item
}
child = child.$$nextSibling;
}
It's probably time to rethink your strategy
I'm not sure what your end goal is, but you might want to rethink how you're going about it and why. Why do you need programmatic access to $pristine in your controller? What alternatives are there? Etc.
I, for one, would try to leverage an ng-change event and update some flag on my item in my repeater, and leave the ng-form stuff for validation:
<div ng-repeat="item in items track by $index" ng-form="rptrForm">
<input type="text" name="name" ng-model="item.name" ng-change="item.nameChanged = true" required/>
<span ng-show="rptrForm.name.$error.required>Required</span>
</div>
If you give the <form> element a name attribute, then the <form> will be
added to the $scope object as a property.
Field controller will then be attached to the form property.
As weird as it could seem, you have to define an enclosing form with a name attribute like so:
<form name="myForm">
<input type="text" name="lastName" ng-model="lastname">
</form>
and call the property with:
$scope.myForm.lastname.$dirty
Indeed, ngModelController (field) is attached to ngFormController (form).
I used Ben Lesh's answer to deal with the same problem. I was displaying a list of notification preferences, and my goal was to hit my api with models that had changed. Not just ng-changed, either; value changed.
I start by initializing some private state on my controller:
// Private state
var originalModels = {};
var changedModels = [];
Then I store copies of the original models retrieved from the API:
// Create a hash of copies of our incoming data, keyed by the unique Code
for (var i = 0; i <= data.length - 1; i++) {
var np = data[i];
originalModels[np.Code] = angular.copy(np);
}
Next, we want to make sure that when a model changes, we add it to a changed models collection (or remove it from the collection if no real change occurred):
function modelChanged(m) {
var originalModel = originalModels[m.Code];
var hasChanged = !angular.equals(originalModel, m);
// If the model has changed and is not present in our collection of changed models, add it
if (hasChanged && changedModels.indexOf(m) === -1) {
changedModels.push(m);
}
// If the model has not changed and is present in our collection of changed models, remove it
if (!hasChanged && changedModels.indexOf(m) > -1) {
var i = changedModels.indexOf(m);
changedModels.splice(i, 1);
}
}
Finally, we tie these together in our ng-repeat:
<tr ng-repeat="np in npc.notificationPreferences">
<td>{{np.DisplayName}}</td>
<td>
<input type="checkbox"
ng-model="np.Sms"
ng-checked="np.Sms"
ng-disabled="!np.SmsEnabled"
ng-change="npc.modelChanged(np)"/>
</td>
</tr>
Now, instead of pushing back every row to my API, I simply push the changed models. This also has a side benefit of being able to ng-disable your submit button if nothing has actually changed (ie the changedModels collection is empty).

AngularJS Passing Scope?

I'm actually not sure what the title of the question should be, as it's not clear to me what I am missing.
I have boiled this down to a very simple example (the actual case is more complex). I have a text box and button inside of an ng-switch. The switch, I've read, creates it's own local scope.
What I want to do pass the value of the text box to a function when the button is clicked. In the function, I will do what needs to be done with the value, then clear the text box. I'm struggling to find the right way to do this.
Controller Code:
$scope.temp = 1;
$scope.tempCall = function (tempModel) {
tempModel = ""; //this doesn't work
$scope.tempModel = ""; //nor does this
};
HTML/Template:
<div ng-switch on="temp">
<div ng-switch-when="1">
<input ng-model="tempModel" />
<input type="button" ng-click="tempCall(tempModel)" />
</div>
<div ng-switch-when="2">TWO</div>
</div>
I believe I can actually traverse the scope from the parent or root scope and clear the value, but that doesn't "feel" correct. What is the correct (Angular) way to clear this value?
When you are working with primitive values in angular scopes, you cannot overwrite a value in a parent scope from a child scope. This is because angular uses javascript prototypal inheritance.
What you could do in this case is create an object in the parent scope, then you can update the values on that in the child scope. Because you are not overwriting the object (only properties attached to it) the references work.
I created a demo of this on plunk you can view it here
$scope.temp = 1;
$scope.tempModel = {};
$scope.tempCall = function () {
$scope.tempModel.previous = $scope.tempModel.value
$scope.tempModel.value = "";
};
<div ng-switch on="temp">
<div ng-switch-when="1">
<input ng-model="tempModel.value" />
<input type="button" ng-click="tempCall()" />
{{tempModel.previous}}
</div>
<div ng-switch-when="2">TWO</div>
Here's one way to do it:
<input type="button" ng-click="tempCall(tempModel);tempModel='';" />
Probably the more "Angular way" would be to use a dot in your model like:
<input type="text" ng-model="tempModel.value" />
Then call your function by passing the tempModel object like:
<input type="button" ng-click="tempCall(tempModel)" />
Then you will be able to clear the value with:
$scope.tempCall = function (tempModel) {
tempModel.value = "";
};
Here is a fiddle
To prevent databinding issues, "the rule of thumb is, if you use ng-model there has to be a dot somewhere." Miško Hevery

How can I capture a field name (not field value) with Javascript?

I'm trying to find out how I can use javascript to capture the name of a field and assign the name to a variable. I've done a good amount of searching, but I can only find out how to capture the value of a field and not the name of the field itself.
For example, say I have a asp textbox named "ClientFName". I'd like to use javascript to capture the name of the textbox (ClientFName) and assign the name to a variable.
I'm moderately experienced with javascript but I haven't figured out a way to make this happen. Any help would be great!
You need to find the element in the DOM (which I assume you can do since you can get the value). Then use .name to access its name property, which you can then assign to a variable.
var myName = document.getElementById("myTextbox").name;
By getAttribute() method you can get the attribute value, just check this:
<script>
function check(){
var v= document.getElementById('mytext').getAttribute('name');
alert(v);
}
</script>
<input type="text" id="mytext" value="test" name="mytext1" />
<input type="submit" name="submit" value="submit" onclick="check();"/>

Categories

Resources