Pass angularJS $index into onchange - html

I have an input file within a ng-repeat in my angularJS app. I need to pass the $index variable to the onchange attribute. I'm using onchange and not ng-change because I need the uploaded object (see this post)
In the following code I get 'Uncaught ReferenceError: $index is not defined'
Jade code sample:
div.input-group(ng-repeat='filename in filenames track by $index')
input(type='file', onchange="angular.element(this).scope().file_changed(this.files, **$index**)")

In the onchange attribute, the scope is only accessible via angular.element(this).scope(). That's the method you use to call the file_changed() function, and you should use the same in order to have access to the $index attribute:
<input type="file" onchange="angular.element(this).scope().file_changed(this.files, angular.element(this).scope().$index)" />
Notice that this is becoming pretty long! A solution is to simply pass the DOM element to the function, and obtain all the informations from it:
<input type="file" onchange="angular.element(this).scope().file_changed(this)" />
$scope.file_changed = function (element) {
var index = angular.element(element).scope().$index;
var files = element.files;
// …
};

Related

Function is not defined ReferecenError onchange in Angularjs

I'm having issues with onchange event for file input.
Here is my code:
Html:
<input type="file" kendo-upload k-options="uploadOptions" id="fileInput" onchange="fileUploaded(event)"/>
Angularjs code - using Typescript.
$scope.fileUploaded = (event) => {
console.log("Testing file upload");
var reader = new FileReader();
var target = event.target || event.srcElement;
reader.onload = function(e) {
$scope.$apply(function() {
$scope.readFile = reader.result;
});
};
var file = target.files[0];
reader.readAsText(file);
};
I tried to follow this and change accordingly but am still having issues.
Pass angularJS $index into onchange
I changed like this.
<input type="file" kendo-upload k-options="uploadOptions" id="fileInput" onchange="angular.element(this).scope().fileUploaded(this)">
I got this error.
Uncaught TypeError: undefined is not a function.
onchange
When I am trying to use ng-change, I have this error.
<div kendo-window="importFile" k-visible="false" k-modal="true" k-title="'Import File'"
k-min-width="450" k-max-width="450"
k-min-height="418" k-max-height="418">
<form kendo-validator="validator" ng-submit="validate($event)">
<li style="padding-bottom: 5px;">
<input type="file" kendo-upload k-options="uploadOptions" id="fileInput" ng-change="fileUploaded($event)"/>
</li>
</form>
</div>
This gives error when accessing this
$scope.importFile.center();
"TypeError: Cannot read property 'center' of undefined"
Again, works fine if I use ng-click.
Any help on this is higly appreciated.
Thanks!
You cannot use ngChange in this case since ngChange always requires ngModel and ngModel doesn't work with input type file. Also, you cannot access a function binded to $scope directly using onchange. Instead use the following:
onchange="angular.element(this).scope().fileUploaded($event)"

updated to newest version of polymer and input validation is no longer working

<paper-input
id="server"
floatinglabel=""
label="Server Address"
value=""
required
type="URL">
</paper-input>
the example above worked until the latest polymer update now even the required attribute does nothing. was there some change to core-input that i am missing in documentation? all my inputs with patterns, numbers, urls, or emails nothing causes it to get the invalid class.
<paper-input-decorator
id="address"
labelVisible
floatinglabel
error="URL Required"
label="Server Address">
<input is="core-input" type="URL" id="server" required>
</paper-input-decorator>
above is the updated markup for checking input of url. before the changes the input had invalid by default cause the field was required and updated as you type.
with the new changes you have to call a function to get the input to return the invalid class. (you could put a event listener on the input and run that function every time the input is updated. but i only check on attempted submission) to check i put all the inputs i want to check in a container (a div with a id) then when user click to submit i run the function below.
validate: function (id) {
'use strict';
var $d = document.getElementById(id).querySelectorAll('paper-input-decorator');
Array.prototype.forEach.call($d, function(d) {
d.isInvalid = !d.querySelector('input').validity.valid;
});
}
and pass in the id of the input container. validate(id);
that will cause the input to display the invalid class if input doesn't meet type / pattern requirement. you can then check for invalid class in the same method as before.
invalid = document.querySelector("#address").classList.contains("invalid");
outside a custom element or
invalid = this.$.address.classList.contains("invalid");
inside custom element
then some logic to check for invalid class before running the save function
if (!invalid) {
save();
}
also keep in mind that the decorator and input both have a id. the id on the decorator is used to check for validity while the id on the input is there for getting the value from the committedValue attribute.
info above is for the master branch pulled after 10 - 16 - 14

Empty action attribute on a form with angularJS

I'm trying to submit a form the normal way in a AngularJS application but I encounter an issue : it seems that I must specify the action attribute.
According to the HTML specifications (http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#form-submission-algorithm) :
If action is the empty string, let action be the document's address of
the form document.
But AngularJS refuses to submit the form if the action attribute is not filled.
A work-around I found would be to use action="#" but this is not an acceptable solution since I might use the hash and I don't want it to be rewritten.
Has anyone ever experienced this issue ?
Edit : I don't want to use angular for this form, I just want to submit it the "old" way
I created a small directive to solve this:
.directive('form', ['$location', function($location) {
return {
restrict:'E',
priority: 999,
compile: function() {
return {
pre: function(scope, element, attrs){
if (attrs.noaction === '') return;
if (attrs.action === undefined || attrs.action === ''){
attrs.action = $location.absUrl();
}
}
}
}
}
}]);
Seems to be good for me. It looks for a form where the action is empty, and sets it to the current url.
Actually, it doesn't set the action - it sets the attr value, so the actual form directive thinks it's got one.
Update by #Reimund is good - I have actually had to do the same.
New Update - I have added the option to add a noaction attribute to the form element; this enables you to return to a "normal" angular situation. Otherwise this directive will submit forms twice if using ajax.
In the library, you can see that Angular listens to the event submit of your forms without action : https://github.com/angular/angular.js/blob/b9fa5c5a6781f4e1ec337f27d55c69db491a6555/src/ng/directive/form.js#L331
You can comment this line, it works, but I'm against editing the code of libraries.
Few lines after, you can see that Angular listening to the event $destroy enabling to remove the action on this event.
Therefore, to avoid modifying Angular, you can just trigger this event of your form:
angular.element(document).ready(function(){
angular.element(document.querySelector("#loginForm")).triggerHandler("$destroy")‌​;
});
The reason of this behavior is described few lines above:
we can't use jq events because if a form is destroyed during submission the default action is not prevented.
And the related issue is: https://github.com/angular/angular.js/issues/1238
You can use ng-submit.
Form
<form name="test" action="" ng-submit="submit()">
What's your name? <input ng-model="name" /><br />
<button>Send</button>
</form>
<br />
My name is: {{name}}
JS
var app = angular.module('App', []);
app.controller('AppCtrl', function($scope) {
$scope.submit = function() {
$scope.name = $scope.name + ' Doe';
}
});
Plunker http://plnkr.co/edit/rqAwxWmozrzwwj4oAU5k?p=preview
Normally I simply make button with ng-click handler.
<button ng-click="Generate()">Submit</button><br>

How can I detect keydown or keypress event in angular.js?

I'm trying to get the value of a mobile number textbox to validate its input value using angular.js. I'm a newbie in using angular.js and not so sure how to implement those events and put some javascript to validate or manipulate the form inputs on my html code.
This is my HTML:
<div>
<label for="mobile_number">Mobile Number</label>
<input type="text" id="mobile_number" placeholder="+639178983214" required
ngcontroller="RegisterDataController" ng-keydown="keydown">
</div>
And my controller:
function RegisterDataController($scope, $element) {
console.log('register data controller');
console.log($element);
$scope.keydown = function(keyEvent) {
console.log('keydown -'+keyEvent);
};
}
I'm not sure how to use the keydown event in angular.js, I also searched how to properly use it. And can i validate my inputs on the directives? Or should I use a controller like what I've done to use the events like keydown or keypress?
Update:
ngKeypress, ngKeydown and ngKeyup are now part of AngularJS.
<!-- you can, for example, specify an expression to evaluate -->
<input ng-keypress="count = count + 1" ng-init="count=0">
<!-- or call a controller/directive method and pass $event as parameter.
With access to $event you can now do stuff like
finding which key was pressed -->
<input ng-keypress="changed($event)">
Read more here:
https://docs.angularjs.org/api/ng/directive/ngKeypress
https://docs.angularjs.org/api/ng/directive/ngKeydown
https://docs.angularjs.org/api/ng/directive/ngKeyup
Earlier solutions:
Solution 1: Use ng-change with ng-model
<input type="text" placeholder="+639178983214" ng-model="mobileNumber"
ng-controller="RegisterDataController" ng-change="keydown()">
JS:
function RegisterDataController($scope) {
$scope.keydown = function() {
/* validate $scope.mobileNumber here*/
};
}
Solution 2. Use $watch
<input type="text" placeholder="+639178983214" ng-model="mobileNumber"
ng-controller="RegisterDataController">
JS:
$scope.$watch("mobileNumber", function(newValue, oldValue) {
/* change noticed */
});
You were on the right track with your "ng-keydown" attribute on the input, but you missed a simple step. Just because you put the ng-keydown attribute there, doesn't mean angular knows what to do with it. That's where "directives" come into play. You used the attribute correctly, but you now need to write a directive that will tell angular what to do when it sees that attribute on an html element.
The following is an example of how you would do that. We'll rename the directive from ng-keydown to on-keydown (to avoid breaking the "best practice" found here):
var mod = angular.module('mydirectives');
mod.directive('onKeydown', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
// this next line will convert the string
// function name into an actual function
var functionToCall = scope.$eval(attrs.ngKeydown);
elem.on('keydown', function(e){
// on the keydown event, call my function
// and pass it the keycode of the key
// that was pressed
// ex: if ENTER was pressed, e.which == 13
functionToCall(e.which);
});
}
};
});
The directive simple tells angular that when it sees an HTML attribute called "ng-keydown", it should listen to the element that has that attribute and call whatever function is passed to it. In the html you would have the following:
<input type="text" on-keydown="onKeydown">
And then in your controller (just like you already had), you would add a function to your controller's scope that is called "onKeydown", like so:
$scope.onKeydown = function(keycode){
// do something with the keycode
}
Hopefully that helps either you or someone else who wants to know
You can checkout Angular UI # http://angular-ui.github.io/ui-utils/ which provide details event handle callback function for detecting keydown,keyup,keypress
(also Enter key, backspace key, alter key ,control key)
<textarea ui-keydown="{27:'keydownCallback($event)'}"></textarea>
<textarea ui-keypress="{13:'keypressCallback($event)'}"></textarea>
<textarea ui-keydown="{'enter alt-space':'keypressCallback($event)'}"> </textarea>
<textarea ui-keyup="{'enter':'keypressCallback($event)'}"> </textarea>
JavaScript code using ng-controller:
$scope.checkkey = function (event) {
alert(event.keyCode); //this will show the ASCII value of the key pressed
}
In HTML:
<input type="text" ng-keypress="checkkey($event)" />
You can now place your checks and other conditions using the keyCode method.

html5 form checkValidity() method not found

I am trying to use the form method checkValidity().
http://html5test.com/ tells me that my browser (Chrome) support the form-level checkValidity method.
However, using jsfiddle http://jsfiddle.net/LcgnQ/2/ I have tried the following html and javascript snippets:
<form id="profileform" name="profileform">
<input type="text" id="firstname" required>
<input type="button" id="testbutton" value="Test">
</form>
$('#testbutton').bind('click',function(){
try{
alert($('#profileform').checkValidity());
}
catch(err){alert('err='+err)};
});
I'm getting an error: object has no method checkValidity()
What am I doing wrong?
Try:
$('#profileform')[0].checkValidity()
When you select $('#profileform') you get a jQuery object array. To access actual DOM properties you must select the first item in the array, which is the raw DOM element.
#robertc 's Answer is perfect. Anyway I'd just add another way to do it using jQuery's .get([index]) function. It also retrieves the DOM element for the given index, or all of the matched DOM elements if there's no index declared.
In the end it is exactly the same, only written in a bit more verbose way:
$('#profileform').get(0).checkValidity()
Leaving you the docs right here: https://api.jquery.com/get/
Just another way:
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.getElementsByName('profileform');
// Loop over them and prevent submission
var validation = Array.prototype.filter.call(forms, function (form) {
form.addEventListener('submit', function (event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
}, false);
});