ng-disabled on inputs from ng-repeat loop - javascript

I'm displaying inputs basing on array like this
<div data-ng-repeat="n in langInput.values">
<input type="text"
id="auction_name_{{n.selected}}"
class="form-control"
name="auction_name_{{$index}}"
data-ng-model="inputs.auction_name[$index + 1]"
data-ng-minlength="5"
data-ng-maxlength="60"
required />
<span data-ng-show="sellItem['auction_name_'+$index].$error.required">Wymagane!</span>
It also give's me ability of angularjs validation. Next after <form> is closed I want to create "next" button but I also want to do validation there so if user don't fullfill required inputs he will not be able to click it.
Array which I'm ng-repeating on is:
$scope.langInput = {
count: 3,
values: [
{
id: "1",
selected: "pl"
},
{
id: "2",
selected: "eng"
}
],
add: function () {
if (this.count < 7) {
this.values.push({id: this.count, selected: "eng"});
this.count += 1;
console.log(this.values);
}
},
remove: function () {
if (this.count > 2) {
this.values.pop();
this.count -= 1;
console.log(this.count);
}
}
};
I know I can use this ng-disabled directive however I don't know how I can check this inputs which are displayed in loop because its name is changing depending on $index of loop.
I've created plunker
My situation is that I know that I can disable button when some of element is invalid by ng-disabled="sellItem.$error" but in my form in real project I have this form much bigger and I have many ways of acomplishing form so in the end when user finish fullfilling form user still got some of inputs which are not even shown invalid.
So I can't use ng-disabled="sellItem.$error" because after user complete form he still got invalid inputs in background.
I also can not split form to many little forms because it will call 1 endpoint on submit.
What I did in real project is inject 3 different buttons and show them on correct step. Every of this button need to have ng-disabled to not let user to go to next step without completing step' inputs.
So intead of ng-disabled="sellItem.$error" I need to specify all inputs in ng-disabled of one step ( which is about 5 inputs ).
So it would look something like this:
ng-disabled="sellItem.first_input.$error &&
sellItem.second_input.$error && ..."
And I would do this but then I come to problem that I can't "loop" inside of ng-disabled and I want to "loop" inside it because names of inputs are generated by JS
name="auction_name_{{n.id}}"
they and not constant they change, user can add more inputs and delete them
at page start I have two inputs which after JS run are name="auction_name_1" and name="auction_name_2" (due to binding interpolated value) and then user can and third one name="auction_name_3"so I can't also hardcode them within ng-disabled.

I don't know how I can check this inputs which are displayed in loop because its name is changing depending on $index of loop.
Generally one stores the input as a property of the object in the array so that it stays with the object as its position in the array changes.
Also use the id property of the object:
<form name="sellItem" ng-submit="submit()">
<div data-ng-repeat="n in langInput.values">
<input type="text"
id="auction_name_{{n.selected}}"
class="form-control"
̶n̶a̶m̶e̶=̶"̶a̶u̶c̶t̶i̶o̶n̶_̶n̶a̶m̶e̶_̶{̶{̶$̶i̶n̶d̶e̶x̶}̶}̶"̶
name="auction_name_{{n.id}}"
̶d̶a̶t̶a̶-̶n̶g̶-̶m̶o̶d̶e̶l̶=̶"̶i̶n̶p̶u̶t̶s̶.̶a̶u̶c̶t̶i̶o̶n̶_̶n̶a̶m̶e̶[̶$̶i̶n̶d̶e̶x̶ ̶+̶ ̶1̶]̶"̶
data-ng-model="n.input"
data-ng-minlength="5"
data-ng-maxlength="60"
required />
<span data-ng-show="sellItem['auction_name_'+n.id].$error.required">Wymagane!</span>
<span data-ng-show="sellItem['auction_name_'+n.id].$error.minlength">Za krótkie!</span>
<span data-ng-show="sellItem['auction_name_'+n.id].$error.maxlength">Za długie!</span>
</div>
<button type="submit" ng-disabled="sellItem.$error">
{{Submit}}
</button>
</form>
Be sure to generate unique values for the id property.
Update
Added Submit button.
For more information, see
AngularJS Developer Guide - forms
AngularJS <form> Directive API Reference
AngularJS ng-submit Directive API Reference

Related

Angular - trouble with properties updating onchange from checkbox

I am attempting to use a checkbox in Angular in order to toggle the contents of an array. I am using property booleans to determine if 3 different boxes are checked and adjust the contents of the array accordingly. The array defaults to containing all 3 subarrays via declaring this.allNouns in ngOnInit(). When I click the first checkbox, I can see in the console that it is running the associated onchange function and setting the associated boolean to its opposite, but the interpolated string in the view does not change. When I click it again, it will change the view but now everything is one step behind. Also when it hits the console logs, it appears to load the prior length and not the length of the newly established this.allNouns. Below are the html and ts snippets associated with it. This is the first of the three checkboxes, but I plan to apply it to all when smoothed out.
TS
preloadedNouns: Boolean = true;
toggleData() {
if(this.preloadedNouns==false){
this.allNouns=this.nouns.concat(this.onlyUserNouns);
console.log('hitting first condition in toggledata', this.allNouns.length);
}
else {
this.allNouns=this.nouns.concat(this.stockNouns).concat(this.onlyUserNouns);
console.log('hitting second condition in toggledata', this.allNouns.length);
}
}
HTML
<div name="allNouns" [(ngModel)]="allNouns" [ngModelOptions]="{standalone: true}" ngDefaultControl>{{allNouns.length}}</div>
<div class="toggleDiv">
<label>Preloaded Nouns</label>
<input id="preloadedNounsCheck"
type="checkbox"
[checked]="preloadedNouns"
(change)="toggleData(); preloadedNouns = !preloadedNouns">
</div>
i don't clear about your nouns logic.
<div class="toggleDiv">
<label>Preloaded Nouns</label>
<input id="preloadedNounsCheck"
type="checkbox"
[checked]="preloadedNouns"
(change)="preloadedNouns = !preloadedNouns;toggleData()">
</div>
but i hope based on my understanding above code will help to you.
just reorder the function call in (change).

Meteor: Creating a single CMS form

So I am having difficulty creating a single form that, when updated, updates HTML text.
For example, on page 1 of my site, there is a form with the words TITLE written in it. Now on page 2 the only words on the page are TITLE. Now I want to be able to update that form to now say TITLE 2 and have is update page 2 instantly.
I want to make lots of these forms so what is the way to do this with the least amount of code?
If your form and the element showing your text are in different template, you have to use Session.
In your first template (page 1): Attach an event to your input so when you type text you update the Session variable.
In your second template (page 2): Use a simple helper returning the value of the Session variable
Here's the code:
<template name="page1">
<input type="text" class="js-change-text">
</template>
Template.page1.events({
"keyup .js-change-text"(event, instance) {
let inputValue = event.target.value);
Session.set('inputValue', inputValue);
},
});
<template name="page2">
<h1>{{getInputValue}}</h1>
</template>
Template.page2.helpers({
getInputValue() {
return Session.get('inputValue');
},
});

ng-model misbehaving with HTML reset method

Im trying to be as ellaborative as i can with my question....
Scenario:
I have three input fields in my html page Two of them are to accept user inputted values and the third one binds(adds) these two values.
Done so far:
I initially used <input value="{{value1+value2}}" id="value3"/> which took the values as string; solved this issue by substracting the string by 0. But, this calculated values wont go off even using the reset button.
Then someone here on SOF told me to use <input ng-model="(value1-0)+(value2-0)" id="value3"/> which works, but i noticed that even though the values disapper visually the model still holds some value.
(When, i enter some value into the first input field, the third calculated field add the value of the inputted field with the previous value of the second input field(value that the second field had previous to the reset)
NOTE:
Reset method resets the values of the first two user inputted fields, but not that of the third calcualtion field while using <input value="{{value1+value2}}" id="value3"/> OR <input ng-bind="value1+value2" id="value3"/>
While, when using <input ng-model="(value1-0)+(value2-0)" id="value3"/> the calculated field is visually cleared but when i enter some value into one of the user inputted fields(value1 or value2) the calculated field adds the entered number with the previous number that the field ccontained.
I tried many ways to solve this issue, but with no suuccess.... can someone please guide me through?
Thanks in advance.....
Here's a simple fiddle . Follow the link and take a look.
Basically, to have only number values in the user inputed fields, I used HTML5 number inputs, readily available in any newer browser.
<div ng-controller="MyCtrl">
<input type="number" ng-model="value1" />
<input type="number" ng-model="value2" />
<input type="text" ng-model="value1 + value2" />
<button type="button" ng-click="reset()">RESET</button>
</div>
And as for the javascript, here is my controller:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', MyCtrl)
function MyCtrl($scope) {
$scope.value1 = '';
$scope.value2 = '';
$scope.value3 = '';
$scope.reset = function() {
$scope.value1 = '';
$scope.value2 = '';
$scope.value3 = '';
};
}
The three values are first initialized as empty strings, and on ng-click of the RESET button, they are nullified again.
NOTE: For the sake of simplicity I used number inputs instead of trying to implement some kind of javascript validation which I would suggest for production level. The point of my answer was just to explain the principle using the most basic concepts.

Homemade "Captcha" System - One minor glitch in javascript, can't enable submit button

So basically what I'm trying to do as a measure of security (and a learning process) is to my own "Capthca" system. What happens is I have twenty "label's" (only one shown below for brevity), each with an ID between 1 and 20. My javascript randomly picks one of these ID's and makes that picture show up as the security code. Each label has its own value which corresponds to the text of the captcha image.
Also, I have the submit button initially disabled.
What I need help with is figuring out how to enable the submit button once someone types in the proper value that matches the value listed in the HTML label element.
I've posted the user input value and the ID's value and even when they match the javascript won't enable the submit button.
I feel like this is a really really simple addition/fix. Help would be much much appreciated!!!
HTML code
<div class="security">
<label class="captcha enabled" id="1" value="324n48nv"><img src="images/security/1.png"></label>
</div>
<div id="contact-div-captcha-input" class="contact-div" >
<input class="field" name="human" placeholder="Decrypt the image text here">
</div>
<input id="submit" type="submit" name="submit" value="Send the form" disabled>
Javascript code
//Picks random image
function pictureSelector() {
var number = (Math.round(Math.random() * 20));
//Prevents zero from being randomly selected which would return an error
if (number === 0) {
number = 1;
};
console.log(number);
//Set the ID variable to select which image gets enabled
pictureID = ("#" + number);
//If the siblings have a class of enabled, remove it
$(pictureID).siblings().removeClass("enabled");
//Add the disabled class to all of the sibling elements so that just the selected ID image is showing
$(pictureID).siblings().addClass("disabled");
//Remove the disabled class from the selected ID
$(pictureID).removeClass("disabled");
//Add the enabled class to the selected ID
$(pictureID).addClass("enabled");
};
//Calls the pictureSelector function
pictureSelector();
//Gets the value of the picture value
var pictureValue = $(pictureID).attr("value");
console.log(pictureValue);
//Gets the value of the security input box as the user presses the keys and stores it as the variable inputValue
$("#contact-div-captcha-input input").keyup(function(){
var inputValue = $("#contact-div-captcha-input input").val();
console.log(inputValue);
});
console.log($("#contact-div-captcha-input input").val());
//Checks to see if the two values match
function equalCheck() {
//If they match, remove the disabled attribute from the submit button
if ($(pictureValue) == $("#contact-div-captcha-input input").val()) {
$("#submit").removeAttr("disabled");
}
};
equalCheck();
UPDATE
Fiddle here
UPDATE #2
$("#contact-div-captcha-input input").keyup(function(){
var inputValue = $("#contact-div-captcha-input input").val();
console.log(inputValue);
if (pictureValue === inputValue) {
$("#inputsubmit").removeAttr("disabled");
}
});
So I got it working 99.9%, now the only problem is that if someone were to backspace or delete the correct value they have inputted, the submit button does not then change back to disabled. Any pointers?
Known issue.
Give your button a name OTHER THAN submit. That name interferes with the form's submit.
EDIT
A link was requested for this -- I don't have a link for pure JavaScript, but the jQuery docs do mention this issue:
http://api.jquery.com/submit/
Forms and their child elements should not use input names or ids that
conflict with properties of a form, such as submit, length, or method.
Name conflicts can cause confusing failures. For a complete list of
rules and to check your markup for these problems, see DOMLint.
EDIT 2
http://jsfiddle.net/m55asd0v/
You had the CSS and JavaScript sections reversed. That code never ran in JSFiddle.
You never re-called equalCheck. I added a call to your keyUp handler.
For some reason you wrapped pictureValue inside a jQuery object as $(pictureValue) which couldn't have possibly done what you wanted.
Basic debugging 101:
A console.log inside of your equalCheck would have shown you that function was only called once.
A console log checking the values you were comparing would have shown
that you had the wrong value.
Basic attention to the weird highlighting inside of JSFiddle would have shown you had the code sections in the wrong categories.

Knockout - Checking checkboxes according to observableArray

So I have a list of schedules that I need to display for a user and show which schedules he or she is currently on and give them the possibility to jump on and off said schedules.
My viewmodel looks like this
self = this;
self.shifts = ko.observableArray();
self.selectedShifts = ko.observableArray();
//I populate self.shifts here with a WEB API call
//Run through each shift and check if current user is on it and set checked / not checked value for checkbox
ko.utils.arrayForEach(self.shifts(), function(shift) {
//Clear array
self.usersOnShift([]);
//Populate array with all users on the shift
self.usersOnShift = ko.observableArray(WEB API CALL HERE);
var userInShift = ko.utils.arrayFirst(self.usersOnShift(), function(user) {
if (selectedUserId == user.ID) {
return true;
}
});
if (userInShift) {
self.selectedShifts.push(shift.ID);
}
});
ko.applyBindings(self);
My HTML looks like this
<div class="simple_overlay" id="shiftOverlay">
<div class="details">
<div data-bind="foreach: shifts">
<div><span class="staff-initials" data-bind="text:wardName"> </span><input type="checkbox" data-bind="value: ID, checked: $root.selectedShifts"/> </div>
</div>
<div>
Connect
Close
</div>
</div>
</div>
I can see that the value of the checkboxes are set correctly to the ID of the corresponding shifts. However a shift that I know the user in question is on is not checked and I know that the selectedShifts observableArray contains the value.
Somehow the "checked: $root.selectedShifts" call / check is not working but I know that it contains the right value. What am I doing wrong?
The problem is that your value is an integer, but when bound to the checkbox element, it becomes a string. When the checked binding tries to find the value in the array, it doesn't find a match because it uses strict equality for comparison and (2 === "2") is false.
The simplest way to work around this problem is to convert your values to string when you add them to the array:
self.selectedShifts.push("" + shift.ID);
Of course this means that your model has to change, and that might not be a great solution. I came up with a custom binding, checkedInArray that replaces checked and supports any type of value. You can learn about it, see it in action, and use it like this:
<input type="checkbox" data-bind="checkedInArray: {value: ID, array: $root.selectedShifts }" />
In Knockout 2.3.0 (which is still in development) there will be a new binding, checkedValue, that will allow you use any type of value with the checked binding. Using that version, you could update your HTML to use checkedValue:
<input type="checkbox" data-bind="checkedValue: ID, checked: $root.selectedShifts"/>
Is shift.ID an observable property? If it is, then you need to add it to the array like this:
self.selectedShifts.push(shift.ID());
Otherwise you're just adding the whole observable to the array, and not the value.

Categories

Resources