I have a multiple page (view) sign up form and on view 3 I have an input with an ng-pattern to evaualte a postal/zip code. The problem is when I switch views and then revisit the view with the ng-pattern the input becomes invalid.
<input type="text" class="form-control" name="postal" ng-model="user.postal" ng-minlength="1" ng-maxlength="8" maxlength="8" ng-pattern="/(^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ]( )?\d[ABCEGHJKLMNPRSTVWXYZ]\d$)|(^\d{5}(-\d{4})?$)/gmi" required>
Any ideas on why this becomes invalid?
Here's a snippet of working code that maintains a valid zip code, and user name, when switching between views. I changed your pattern string to make it work for me, but yours might be fine. I just wanted something simpler to test with. The pattern matches xxxxx | xxxxx-xxxx .
The user object is displayed on each view.
The Zip code only shows when it's valid.
If you're using ngView, I found it easiest to nest inside a controller, and remove the controller option from the route configuration. When ngview is updated, it looks like a new controller is instantiated, and you get a new scope. Your previous input would be lost, and well, not be valid :)
var testApp = angular.module("testApp", ['ngRoute']);
testApp.config(['$routeProvider',
function($routeProvider) {
//Every View here shares the same controller. ng-view will give you a new controller if you pass it in.
$routeProvider.when("/view1", {
//Use TemplateURL instead to reference an extrnal page
template: '<h2> view 1 </h2><br/>Zip: <input type="text" class="form-control" name="postal" ng-model="user.postal" ng-pattern="/^\\d{5}$|^\\d{5}-\\d{4}$/" ng-required="!user.postal" /><br/>{{user}}'
//controller: testCtrl * Maybe this is your issue. *
})
.when("/view2", {
//Use TemplateURL instead to reference an extrnal page
template: '<h2> view 2 </h2>Name: <input type="text" class="form-control" name="uname" ng-model="user.name" required /> <br /> {{user}}'
});
}
]);
testApp.controller("testCtrl", function($scope, $http) {
$scope.user = {};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.11/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.1/angular-route.js">
</script>
<div ng-app="testApp">
<div ng-controller="testCtrl">
View 1
<br/>
View 2
<ng-view></ng-view>
</div>
</div>
Related
I'm new AngularJS, I'm trying to test the most basic form using AngularJS in JSFiddle. I'm not sure if I forget to configure anything in JSFiddle, but it is not working and it should.
I followed a basic sample from here.
I also include the CDN from here.
Here is the Angular code:
var app = angular.module('myApp', []);
app.controller('formCtrl', function($scope) {
$scope.firstname = "John";
});
Link to my Fiddle: http://jsfiddle.net/bheng/tth4guev/
Settings
include
How would one go about debugging this further?
There are two things missing
(i) You need to add ng-app directive as follows,
<div ng-app="myApp" ng-controller="formCtrl">
(ii) Change the angular.js script version above 1.1 to use without a global controller, and change load type as No wrap in <head>
WORKING FIDDLE
I see, you did not add a name to your controller,and Angular App but in the JS you are accessing 'formctrl'. Go ahead and add a div around the form and add a ng-app='myApp' and a ng-controller='form-ctrl' to your form and it should work.
You need to wrap the form tag in a div tag with ng-app attribute. Your h1 tag should be encapsulated within the div tag as well...
Here's a working example:
<div ng-app="">
<form>
First Name: <input type="text" ng-model="firstname">
</form>
<h1>You entered: {{firstname}}</h1>
</div>
So here's the thing I saw with your code:
You need to add the name of the App and the controller to the div.
Also you are repeating the name of the person in both fields, if you wish you can make an object with the person information to access each of his data fields:
<div ng-app="myApp" ng-controller="formCtrl">
<form>
Email: <input type="text" ng-model="person.firstname" />
Password: <input type="text" ng-model="person.password" />
</form>
<h1>You entered: {{ person.firstname }}</h1>
</div>
<script>
var myApp = angular
.module("myApp",[])
.controller("formCtrl", function($scope) {
//here's the object called "person":
var person = {
firstname: "John",
password: "password"
};
$scope.person = person;
});
</script>
I'm trying to write a simple page with a couple of inputs which should be required to not be empty.
Here's the code to do that (self-contained):
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
var app = angular.module("myApp", []);
app.controller('myController', ['$scope', function($scope) {
}]);
</script>
<style>
input.ng-invalid {
background-color: pink;
}
input.ng-valid {
background-color: lightgreen;
}
</style>
</head>
<body ng-app="myApp">
<div ng-controller="myController">
Description: *<input type="text" id="input-description" ng-model="req-text" required></input><br/>
Order: *<input type="number" id="input-order" ng-model="req-number" value="100" step="100" required></input><br/>
</div>
</body>
</html>
What I was hoping it would do is start with the text field being blank and red (invalid), and the number field being 100 and green (valid).
The first thing I tried was setting both ng-models for the inputs to the same thing, but that caused the number field to update the text field when it was updated (but not the other way around).
Since that obviously didn't work, I tried using different models for the inputs, as shown in my code. However, now both inputs have a value of 0 (even the text field, which should still be blank), and both inputs cannot be typed into or otherwise edited.
What am I doing wrong, and how do I just get both inputs to be required separately by Angular?
What you're doing wrong first of all is using illegal identifiers for models. req-number is not a valid identifier for a variable. (remember all of these models are actually refered as $scope.variableName, imagine $scope.req-number). Hence your inputs are made readonly. You can actually see that when you examine console of your browser.
Second, html attribute value is ignored for input in this case. Use controller function to set default values for your models.
app.controller('myController', ['$scope', function($scope) {
$scope.req_number = 100;
}]);
....
<div ng-controller="myController">
Description: *<input type="text" ng-model="req_text" REQUIRED><br/>
Order: *<input type="number" ng-model="req_number" required><br/>
</div>
Alternatively you can use ng-init to initiate the model. However as mentioned by #developer0333, this is not recommended because initialization logic is part of business logic and with project evolving can get more complicated then just setting primitive values.
<input type="number" ng-model="req_number" ng-init="req_number=100" required><br/>
Plunker with correct code
PS and a small remark, closing tags are ignored for <input>
Can I use ng-model to build up an object over several views?
For instance, say in view1 I have
<input ng-model='myObject.firstName'>
And in view2 I have
<input ng-model='myObject.lastName'>
And in view3 I have
<input ng-model='myObject.email'>
The idea being you could hit a submit button in the last view, and return the object somewhere.
My initial approach to this is to have a service which declares an empty object, then have functions in the service which allow the controllers using the service to add their view input to that object, then return the object.
However I feel like this is quite a roundabout way of doing it!
If anyone could point me in the right direction I would really appreciate it.
You can use a service for that. Here an example with 3 controllers sharing the same object using 3 directives ng-model. Each controller modify the tested.value property, but you can use differents properties of course.
angular.module('test', []).factory('tested', function() {
return {
value : '123'
};
}).controller('ctrl1', function($scope, tested) {
$scope.tested = tested;
}).controller('ctrl2', function($scope, tested) {
$scope.tested = tested;
}).controller('ctrl3', function($scope, tested) {
$scope.tested = tested;
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="ctrl1">
<input type="text" ng-model="tested.value" />
{{ tested.value }}
</div>
<div ng-controller="ctrl2">
<input type="text" ng-model="tested.value" />
{{ tested.value }}
</div>
<div ng-controller="ctrl3">
<input type="text" ng-model="tested.value" />
{{ tested.value }}
</div>
</div>
Since each view has its controller, the only way to share data is with a service of type "provider", "service" or "factory".
You could then modify your object from each controller with the methods you talk about.
In the end, to notify each view something changed, the service methods could raise an event from the service :
$rootScope.$broadcast('somethingChanged', myObject);
And each controller could listen with:
$scope.$on('somethingChanged', function(data) {
});
I have the following resource set up in my AngularJS app:
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
}]);
And by default they are listed like so via the controller:
var phonecatControllers = angular.module('phonecatControllers', []);
phonecatControllers.controller('PhoneListCtrl', ['$scope', 'Phone',
function($scope, Phone) {
$scope.phones = Phone.query();
$scope.orderProp = 'age';
}]);
As you can see I already have a filter but I want a query string based search so that I can use the History to get back to the results after choosing a record, etc.
First question I have here, is that this list actually uses phones.json for the data but I don't specify this anywhere in the code... so how does this work? Presume some magic is happening but I can't see it.
So back to the initial question, I have built the following search controller:
phonecatControllers.controller('SearchCtrl', ['$scope', '$http', '$location', 'Phone',
function ($scope, $http, $location, Phone) {
$scope.keywords = $location.search()['q'];
// The function that will be executed on button click (ng-click="search()")
$scope.search = function() {
$location.path('phones').search('q', $scope.keywords);
$scope.phones= Phone.query($scope.keywords);
}
}]);
So it should use the query string to find the results. But how do I do this? It seems very transparent how the data is pulled from the JSON file. The method should also list data if the query string is there on page load... so perhaps this should be combined into one controller for both the list and search?
The code above doesn't filter the JSON data when I do a search... so the query string isn't being used... but I presume it's because I don't understand how the app knows to look in the 'phones.json' file?
The HTML for the filtering and search:
<div class="control-group">
<label class="control-label">Filter:</label>
<div class="controls">
<input ng-model="$parent.query">
</div>
</div>
<div class="control-group">
<label class="control-label">Sort by:</label>
<div class="controls">
<select ng-model="$parent.orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</div>
</div>
<hr/>
<div ng-controller="SearchCtrl">
<form class="form-search" ng-submit="search()">
<label>Search:</label>
<input type="text" name="q" ng-model="keywords" class="input-medium search-query" placeholder="Keywords...">
<button type="submit" class="btn" ng-click="search()">Search</button>
</form>
</div>
The HTML for the list:
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp"
class="thumbnail phone-listing">
<img ng-src="{{phone.imageUrl}}">
{{phone.name}}
<p>{{phone.snippet}}</p>
</li>
</ul>
OK so to ensure that I understand correctly:
you already have a as-you-type search using Angular's filter filter
this search is implemented using an input bound to a variable named query
you are trying to persist the search terms when changing view and coming back
you want to persist it in the URL
You don't need the new controller or the new input. In the PhoneListCtrl controller, add $scope.query = $location.search().q. This will read the q parameter from the URL and write the value in query, which will automatically fill the input and filter your results.
To do the reverse (ie writing the value of query to the URL), add a ng-change attribute to your input (<input ng-model="query" ng-change="queryChanged()"/>), and add the corresponding function to your controller:
$scope.queryChanged = function () {
$location.search('q', $scope.query)
}
This function will be executed every time the query changes and it will update the URL accordingly. Everything should work out now. See this fiddle.
As a side note, persisting the query in the URL might not be the best idea, as it will remain visible is the user's browser after they have left the search view. You could use session storage, for example.
I'm trying to get started learning AngularJS for an Ionic app I'm working on, and I'm having a little trouble understanding AngularJS having had most previous experience on jQuery which focuses on DOM manipulation rather than frameworking.
If I have the following markup:
<label class="item-input-wrapper">
<i class="icon ion-ios7-chatbubble placeholder-icon"></i>
<input type="text" placeholder="Send a message...">
</label>
<button class="button button-clear button-positive">
Send
</button>
How can I pass the value of the input on to the controller when enter or send is clicked? I'm working on a chat app, so I believe that a model approach is needed so that the message thread can be automatically updated but other than that I have no idea.
Could someone help me out or at least point me in the right direction?
There are several ways to pass value to your controller. Here is the simplest example. As Justin said, you should look into angular basics.
HTML:
<div ng-controller="MyCtrl">
<input type="text" ng-model="foo" placeholder="Enter something" />
<input type="button" ng-click="doSomething()" value="Send" ng-disabled="foo == null" />
</div>
JS:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.foo = null;
$scope.doSomething = function () {
alert("Hello, " + $scope.foo);
}
}
Here is the working fiddle
And I would recommend you to go through this post.
The following markup you posted is the view. What you'll need to do is write a separate JS script called a controller that gets linked to the view. Look into basic Angular tutorials on how to do that and mainly look into how $scope works in Angular.
Your controller will have a function...say:
$scope.foo = function(input) { alert(input); };
From the view, you can pass a value onto the controller with Angular functions such as ng-click.
<a ng-click="foo('this string will be passed in as the text of the alert')">click me</a>