How to use $error.required with ng-repeat? - angularjs

I have the following structure:
// JS
$scope.fields = [
{ text: 'Email', type: 'text', value: '' },
{ text: 'Password', type: 'password', value: '' }
]
// HTML
<div class="user">
<h2 class="header">Log in</h2>
<form name="login">
<input class="form-control" type="{{ field.type }}" placeholder="{{ field.text }}" ng-model="field.value" ng-repeat="field in fields" required />
<a class="btn primary" href="javascript:;" ng-click="login()">Log in</a>
</form>
</div>
How can I implement $error.required like shown here? http://plnkr.co/edit/VLOEfp?p=preview
I don't know where to place:
<div class="" ng-show="myform.routingNumber.$error.required">
<span class="help-block">Please enter routing number</span>
</div>
Maybe I have to re-structure that ng-repeat?

Try something like below. You are almost there. Just missed a basic point, all controls need name. Angular uses name for validations.
<div class="user">
<h2 class="header">Log in</h2>
<form name="login" novalidate="">
<div ng-repeat="field in fields" >
<input class="form-control" type="{{ field.type }}" placeholder="{{ field.text }}" ng-model="field.value" required name="{{field.name}}"/>
<div ng-show="login.{{field.name}}.$invalid">
<span class="help-block">Please enter</span>
</div>
</div>
<a class="btn primary" href="javascript:;" ng-click="login()">Log in</a>
</form>
</div>
Accordingly add name in your controller like below
$scope.fields = [
{ text: 'Email', type: 'text', value: '', name:'idname'},
{ text: 'Password', type: 'password', value: '', name:'password' }
]

In the example code, myform.routingNumber.$error.required myform is the name (html attribute) of your form and routingNumber is the name of your input element which should be validate.
So, like this,
<form name="myform">
<input name="routingNumber" ng-model="myRoute" />
<div class="" ng-show="myform.routingNumber.$error.required">
<span class="help-block">Please enter routing number</span>
</div>
</form>
Implement this on your code
So, in your actual code (with ng-repeat) you have to create a unique name for each input element.
<div class="user">
<h2 class="header">Log in</h2>
<form name="login">
<input class="form-control" name="{{field.text}}" type="{{ field.type }}" placeholder="{{ field.text }}" ng-model="field.value" ng-repeat-start="field in fields" required />
<div ng-repeat-end class="" ng-show="myform[field.text].$error.required">
<span class="help-block">Please enter {{field.text}}</span>
</div>
<a class="btn primary" href="javascript:;" ng-click="login()">Log in</a>
</form>
</div>

Even though #Naga Sandeep has answered the question. I'm just adding another condition to wrap the error message else the error message will be shown even if the user has not touched the form.
<div ng-app="myApp", ng-controller="myCtrl">
<form name="myForm" novalidate="">
<div ng-repeat="info in loginInfo">
<input type="{{info.type}}" ng-model="info.value" name="{{info.name}}" required novalidate>
<span ng-show="myForm.{{info.name}}.$touched || myForm.$submitted">
<span ng-show="myForm.{{info.name}}.$invalid">Please enter this field</span>
</span>
</div>
<button type="submit">
Login
</button>
</form>
</div>
angular.module("myApp", [])
.controller("myCtrl", myCtrl);
function myCtrl($scope){
$scope.loginInfo = [
{"name": "user_email", "value": "", "type":"email"},
{"name": "user_pass", "value": "", "type":"password"}
]
}

Related

AngularJS validations in .NET CSHTML files

My angularjs validation in .NET MVC cshtml files isnt working.
Below is my code:
cshtml code:
<div id="addEditItem" class="modal" role="dialog">
<form novalidate role="form" name="frmItem">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Add Item Details</h4>
</div>
<div class="modal-body">
<input type="hidden" class="form-control" ng-model="id">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" ng-model="name" maxlength="50" ng-required="true">
<span style="color:red" class="help-block" ng-if="frmItem.name.$error.required && frmItem.name.$dirty">*</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><i class="fa fa-close"></i> Close</button>
<button type="submit" class="btn btn-success" ng-click="SaveItem()"><i class="fa fa-save"></i> Submit</button>
</div>
</div>
</div>
</form>
</div>
Controller Code:
medApp.controller("itemController", function ($scope, itemService) {
$scope.SaveItem = function () {
var itemModel = {
Id: $scope.id,
Name: $scope.name,
Description: $scope.description,
Manufacturer: $scope.manufacturer,
BatchNo: $scope.batchNo,
ExpiryDate: $scope.expiryDate
};
if (!CheckIsValid()) {
alert('Please fill the detail!');
return false;
}
var requestResponse = itemService.AddEdit(itemModel);
Message(requestResponse);
};
function CheckIsValid() {
var isValid = true;
if ($('#name').val() === '' || $('#description').val() === '' || $('#manufacturer').val() === '' || $('#batchNo').val() === '') {
isValid = false;
}
return isValid;
}
});
The addEditItem is a modal dialog. If I click on submit the alert('Error in getting records'); is shown.
I want the validation to happen at cshtml level rather than the java alert.
I am going to remove the CheckIsValid function. I want the validation to happen only in cshtml file.
Any idea what's going on?
In your attached cshtml code I could find the "name" id only, but your check function is also checking"description", "manufacturer" and "batchNo". All of those item must be exist otherwise the function returns with false.
The CheckIsValid() function will return true when all items exists and contains at least one character. Anyway the good start is to put a breakpoint into your check code and see why returns with false.
Wordking fiddle
<form name="myForm">
<input type="hidden" class="form-control" ng-model="id">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" name="name" ng-model="name" maxlength="50" ng-required="true">
<span style="color:red" class="help-block" ng-show="myForm.name.$error.required && !myForm.name.$valid">*</span>
</div>
<button ng-click="display()">Log</button>
</form>
Would like to add that you need to add:
Use name on inputs to be accesable from the scope
Use ng-show/ng-hide for validation since it changes alot

Want to add comment at respective places

Below is the structure of threaded comments in angular.js form.
<form>
<ul class="unstyled">
<!-- ng-class="{ '{{childcond}}': $index == selectedIndex }" -->
<li ng-repeat="comment in comments" class="{{childcond}}" ng-init=" childcond=checkChild(comment.slug); reply.parentSlug=comment.slug; idstring=slashRemove(comment.slug);" >
<strong>{{comment.author}}</strong><br>
<p>
{{comment.body}}
</p>
<a href="javascript:void(0)" class="replycomment" >reply</a>
<div id="{{idstring}}" style="display:none;" >
<input type="text" placeholder="Your Name" ng-model="reply.replyAuthor"><br>
<span style="display:none;">
<input type="text" class="hidevalue" ng-model="reply.parentSlug" ng-value="{{comment.slug}}" >
</span>
<textarea name="" id="" cols="30" rows="10" placeholder="Comment" ng-model="reply.replyBody"></textarea>
<input class="btn-primary" type="submit" value="reply" ng-click="replyComment(reply,$index)">
</div>
</li>
</ul>
When i replying to the comment i am getting my comment in last place.
This is my reply code in angular.js file.
$scope.replyComment = function(reply,$index) {
socket.emit('comment', { author: reply.replyAuthor,
body: reply.replyBody,
parent_slug:reply.parentSlug });
clearForm();
};
socket.on('comment', function(comment) {
$scope.$apply(function() {
console.log(comment);
$scope.comments.push(comment);
});
});
console.log(comment) gives following structure.
Any help would be much appreciated!!!

Trigger ng-init manually

I have a profile with a series of cards. Each card has a type (e.g. gallery card, quote card, etc) and the profile can have 1 or more of each type. I'm building a profile editor and want to be able to open an edit form in a modal. Each card has its own type of form with unique inputs, but there is only one form per card type, since we can't know in advance how many cards of each type a profile will have.
For each form, I have a number of ng-init directives to prepopulate the edit form with the current model's attributes. This works great except that if I have more than one card of a type, each card's edit form will have the data from the last card in the set. Is there a way I can trigger the ng-init directives to run again when I open the form (e.g. with an ng-click) so that the user will always see the current model's attributes?
Here is what one of my card forms looks like:
<% if c.class.name == 'QuoteCard' %>
<div class="row-scrollable" ng-show="view === 'quote-card'">
<div class="col-lg-12">
<form accept-charset="UTF-8" name="editQuoteCardForm" ng-submit="update({card: editQuoteCard, type: 'quote_card'})" novalidate>
<input name="utf8" type="hidden" value="✓">
<input name="authenticity_token" type="hidden" ng-model="editQuoteCard.token" ng-init="editQuoteCard.token='<%= form_authenticity_token %>'">
<input name="id" type="hidden" ng-model="editQuoteCard.id" ng-init="editQuoteCard.id='<%= c.id %>'">
<div class="form-group">
<label>Title</label>
<br style="clear:both;" />
<input type="text" class="form-control" name="title" ng-init='editQuoteCard.title = "<%= c.title %>"' ng-model="editQuoteCard.title" required>
</div>
<div class="form-group">
<label>Attribution</label>
<br style="clear:both;" />
<input type="text" class="form-control" name="attribution" ng-init='editQuoteCard.title = "<%= c.attribution %>"' ng-model="editQuoteCard.attribution">
</div>
<div class="form-group">
<label>Quote</label>
<br style="clear:both;" />
<textarea rows="3" class="form-control" name="quote" ng-init='editQuoteCard.title = "<%= c.quote %>"' ng-model="editQuoteCard.quote" required></textarea>
</div>
<div class="form-group">
<label>Media</label>
<br style="clear:both;" />
<input type="hidden" class="form-control" name="photo" ng-model="editQuoteCard.image">
<input type="hidden" class="form-control" name="video" ng-model="editQuoteCard.video">
<%= photo = Photo.find_by(quote_card_id: c.id) %>
<%= video = Video.find_by(quote_card_id: c.id) %>
<div class="profile-builder attachment"
ng-init='<%= "editQuoteCard.image = #{{ image_url: photo.image.url, id: photo.id }.to_json}" unless photo.nil? %>'
ng-init='<%= "editQuoteCard.video = #{{ media_url: video.media_url, media_type: video.media_type, id: video.id }.to_json}" unless video.nil? %>'>
<div ng-show="editQuoteCard.video" class="content video-content result iframe">
<div class="caption delete-btn" ng-click="editQuoteCard.video = undefined;">
<i class="fa fa-times"></i>
</div>
<iframe ng-if="editQuoteCard.video.media_type === 'Youtube'" ng-src="{{editQuoteCard.video.media_url + '?showinfo=0&autohide=1' | trustAsResourceUrl}}" frameborder="0" id="ytplayer" type="text/html"></iframe>
<iframe ng-if="editQuoteCard.video.media_type === 'Vimeo'" ng-src="{{editQuoteCard.video.media_url + '?badge=0&byline=0&title=0' | trustAsResourceUrl}}" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
<div ng-show="editQuoteCard.image" class="content result">
<div class="delete-btn" ng-click="editQuoteCard.image = undefined;">
<i class="fa fa-times"></i>
</div>
<div class="image-container" ng-style="{'background-image': 'url(' + editQuoteCard.image.image_url + ')'}"></div>
</div>
</div>
</div>
<br style="clear:both;" />
<div class="form-group">
<input class="btn btn-primary" style="float:right;" name="commit" type="submit" value="Update Card" ng-disabled="editQuoteCardForm.$invalid">
<div class="btn btn-default" style="float:right;margin-right:10px;" ng-click="openMediaBrowser({type: '<%= c.class %>', id: <%= c.id %>, index: <%= i %>});" ng-show="!editQuoteCard.image && !editQuoteCard.video">Add Media</div>
</div>
</form>
</div>
</div>
<% end %>
And in my controller, I have an edit function that opens the modal with the correct form:
$scope.edit = function(options) {
modal.open({
content: $('#edit_card_' + options.index + '_form'),
elem: $('#edit_card_' + options.index + '_form_container')
})
};

AngularJS string url concat form data

I am trying to send form data from a contact form to a web service by concat string method. I have made a controller who looks like this:
// contact controller
eventApp.controller('contactController', ['$scope', '$http', function($scope, $http) {
$scope.obj = {
val1: 'personName',
val2: 'email',
val3: 'subject',
val4: 'emailMessage'
};
$scope.sendMessage = function(obj) {
var string = '#/path/' + $scope[obj.val1] + '/' + $scope[obj.val2] + '/' + $scope[obj.val3] + '/' + $scope[obj.val4];
//$scope.debug.val = string;
console.log(obj);
};
}]);
How do I make it possible to fill in input values for the values 'personName', 'email', 'subject' and 'emailMessage' like 'John', 'john#email.com', 'webservice' and 'Hello!'? Should I use expressions?
In the DOM console I get an object answer like this when I tap the send button:
Object {val1: "personName", val2: "email", val3: "subject", val4: "emailMessage"}
My HTML is looking like this:
<!-- partial-contact.html -->
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div id="form-container">
<!-- Contact Heading -->
<div class="page-header text-center">
<h1><i class="fa fa-comment"></i> Kontakt</h1>
<p>Ved spørsmål skriv ein epost i kontaktskjemaet under.</p>
</div>
<!-- Form -->
<!-- use ng-submit to catch the form submission and use our Angular function -->
<form id="contactForm" name="contactForm" novalidate ng-submit="contactForm()" ng-controller="contactController" method="post">
<!-- Name -->
<div class="input-group margin-bottom-sm">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<input id="personName" class="form-control" type="text" name="personName" ng-model="contactData.personName" placeholder="Namn *" required />
</div>
<!-- Email -->
<div class="input-group margin-bottom-sm">
<span class="input-group-addon"><i class="fa fa-envelope-o fa-fw"></i></span>
<input id="email" class="form-control" type="email" name="email" ng-model="contactData.email" placeholder="Epost *" required />
</div>
<!-- Subject -->
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-info"></i></span>
<input id="subject" class="form-control" type="text" name="subject" ng-model="contactData.subject" placeholder="Emne *" required />
</div>
<!-- Email Message & Button -->
<div class="input-group">
<div class="input-group-btn">
<!-- Email Message -->
<textarea id="emailMessage" type="text" class="form-control" name="emailMessage" ng-model="contactData.emailMessage" ng-minlength=10 ng-maxlength=300 placeholder="Melding..." required></textarea>
<!-- Button -->
<button id="submit" type="submit" class="btn btn-primary" ng-click="sendMessage(obj)"><i class="fa fa-angle-double-right"></i></button>
</div>
</div>
<br>
</form>
</div>
</div>
</div>
contactData is your object in the controller scope holding the data.
use $scope.contactData[obj.val1] instead of $scope[obj.val1]

First occurrence of $scope.email is not showing

I have an AuthenticationController in a <div>. I am trying to print {{ email }} twice, but it only shows up the second time.
<div class="login" ng-controller="AuthenticationController">
<!-- This DOESN'T show -->
{{ email }}
<div ng-switch on="isLoggedIn()">
<div ng-switch-when="true">
<input ng-click="logout()" type="submit" value="Logout">
</div>
<div ng-switch-when="false">
<!-- This IS shown -->
{{ email }}
<input ng-model="email" type="text">
<input ng-model="password" type="password">
<input ng-click="login()" type="submit" value="Login">
</div>
</div>
</div>
Why is the first {{ email }} not printed?
ngSwitch creates a new scope. Try using an object:
<div class="login" ng-controller="AuthenticationController">
{{user.email}}
<div ng-switch on="isLoggedIn()">
...
...
<input ng-model="user.email" type="text">
Controller:
$scope.user = {
email:""
};

Resources