I've built a basic Angular app that successfully displays the results of an HTTP GET request.
I'd like to include fallback code that displays two static HTML elements in place of the remote content if the GET request fails.
I can just call a vanilla JS function to do DOM manipulation, but I'd like to do this the Angular way. I've read a lot of documentation and articles, but I'm not seeing a straightforward way to do this. Code below.
I'd like to replace the call to updateUIError() with Angular code that performs the same task.
Here's a Plunk: https://plnkr.co/edit/PDwSUCXGNW2cwAIwl9Z9?p=streamer
HTML:
<div class="scene fullheight" id="attractions" ng-app="listApp">
<article class="content">
<h1>Upcoming Events</h1>
<div class="main" ng-controller="ListController as eventsList">
<div class="search">
<label>search: </label>
<input ng-model="query" placeholder="Search for events" autofocus>
<label class="formgroup">by:
<select ng-model="eventOrder" ng-init="eventOrder='start.local'">
<option value="start.local">Date</option>
<option value="name.text">Name</option>
</select>
</label>
<label class="formgroup">
<input type="radio" ng-model="direction" name="direction" checked>
ascending
</label>
<label class="formgroup">
<input type="radio" ng-model="direction" name="direction" value="reverse">
descending
</label>
</div>
<ul class="eventlist">
<li class="event cf" ng-repeat="item in eventsList.events | filter: query | orderBy: eventOrder:direction">
<div class="info">
<h2>{{item.name.text}}</h2>
<p>{{item.start.local | date:"dd MMMM ', ' h:mma"}}</p>
</div>
</li>
</ul>
</div>
</article>
</div>
Angular:
angular.module('listApp', [])
.controller('ListController', ['$scope', '$http', function($scope,$http) {
var eventsList = $scope.eventsList;
$http.get(URI)
.success(function(data) {
console.log(data);
eventsList.events = data.events;
}).error(function() {
updateUIError();
});
}]);
function updateUIError() {
var events = document.querySelector('#attractions article');
events.innerHTML = '<h1>Local Attractions</h1><p>There's lots to do nearby.</p>';
}
You need to create a static error and show it when the error occurs using ngIf
<div class="scene fullheight" id="attractions" ng-app="listApp">
<div ng-controller="ListController">
<article class="content" ng-if="hasUIError">
<h1>Local Attractions</h1>
<p>There's lots to do nearby.</p>
</article>
<article class="content" ng-if="!hasUIError">
<h1>Upcoming Events</h1>
<!-- REST OF THE HTML -->
</article>
</div>
</div>
Then, in your controller, you need to set the flag to false by default:
$scope.hasUIError = false;
And when there's an error in the ajax, set it to true
$http.get(URI).then(
function(response) {
console.log(response);
$scope.events = response.data.events;
},
function() {
$scope.hasUIError = true;
}
);
Before solving your issue, there is another issue to address. Specifically, since you are using the ControllerAs approach, you'll want to attach your variables to 'this' rather than $scope.
Then you create a variable called showError that will get evaluated in showing the message. Then you can use the ng-show directive to hide/show the message.
angular.module('listApp', [])
.controller('ListController', ['$http',
function($http) {
var vm = this;
vm.events = [];
vm.showError = false;
$http.get(URI)
.success(function(data) {
vm.events = data.events;
}).error(function() {
vm.showError = true;
});
}
]);
<!DOCTYPE html>
<html ng-app="listApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.10/angular.min.js" data-semver="1.5.10"></script>
<script src="app.js"></script>
</head>
<body ng-controller="ListController as eventsList">
<div class="scene fullheight" id="attractions">
<div ng-show="eventsList.showError">
<h1>Local Attractions</h1>
<p>There's lots to do nearby.</p>
</div>
<article class="content">
<h1>Upcoming Events</h1>
<div class="main">
<div class="search">
<label>search:</label>
<input ng-model="query" placeholder="Search for events" autofocus>
<label class="formgroup">by:
<select ng-model="eventOrder" ng-init="eventOrder='start.local'">
<option value="start.local">Date</option>
<option value="name.text">Name</option>
</select>
</label>
<label class="formgroup">
<input type="radio" ng-model="direction" name="direction" checked>ascending
</label>
<label class="formgroup">
<input type="radio" ng-model="direction" name="direction" value="reverse">descending
</label>
</div>
<ul class="eventlist">
<li class="event cf" ng-repeat="item in eventsList.events | filter: query | orderBy: eventOrder:direction">
<div class="info">
<h2>{{item.name.text}}</h2>
<p>{{item.start.local | date:"dd MMMM ', ' h:mma"}}</p>
</div>
</li>
</ul>
</div>
</article>
</div>
</body>
</html>
Do something like this:
angular.module('listApp', [])
.controller('ListController', ['$scope', '$http', function($scope,$http) {
var eventsList = $scope.eventsList;
$http.get(URI)
.success(function(data) {
console.log(data);
eventsList.events = data.events;
}).error(function() {
eventsList.errorMessage = '<h1>Local Attractions</h1><p>There's lots to do nearby.</p>';
});
}]);
In the HTML, add a span inside the scope of ListController that will have ngModel="errorMessage". You can add additional property to show / hide the error span and main content div.
Related
hello i have a problem with angular im benninger to this framework but i have some knowledge about it . Yesterday i faced a problem when i wanted to change controller from a global function(in this case all is OK) to controller by module i recive blank page here is my code
angular.module('myApp', ['ngRoute', 'membersService']).config(
['$httpProvider', '$routeProvider', function ($httpProvider, $routeProvider) {
$routeProvider.when('/home', {
templateUrl: 'partials/home.html',
controller: MembersCtrl
}).otherwise({
redirectTo: '/home'
});
}]);
var myApp = angular.module('myApp');
myApp.controller('MembersCtrl',['$scope','$http', 'MembersSrv',function ($scope, $http, MembersSrv) {
$scope.refresh = function () {
return MembersSrv.getAllPersons().then(function (data) {
$scope.persons = data.data;
});
};
$scope.clearMessages = function () {
$scope.successMessages = '';
$scope.errorMessages = '';
$scope.errors = {};
};
$scope.reset = function () {
if ($scope.regForm) {
$scope.regForm.$setPristine();
}
$scope.newPerson = {name: "", lname: "", phoneNumber: ""};
$scope.clearMessages();
};
$scope.register = function () {
$scope.clearMessages();
MembersSrv.save($scope.newPerson, function (data) {
$scope.refresh();
$scope.reset();
$scope.successMessages = ['Member Registered'];
}, function (result) {
if ((result.status == 409) || (result.status == 400)) {
$scope.errors = result.data;
} else {
$scope.errorMessages = ['Unknown server error'];
}
});
};
$scope.refresh();
$scope.reset();
$scope.orderBy = 'name';
}]);
angular.module('membersService', []).service('MembersSrv', [
'$http', function ($http) {
this.getAllPersons = function () {
var url = "http://localhost:8080/gadziksy-web/rest/person";
var req = {
method: 'GET',
url: url,
};
return $http(req);
}
}]);
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<title>myApp</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<!-- Disable phone number detection on iOS. -->
<meta name="format-detection" content="telephone=no"/>
<link rel="stylesheet" href="css/screen.css" type="text/css"/>
<!-- Load angularjs -->
<script src="js/libs/angular.js"></script>
<!-- Load angularjs-route, which allows us to use multiple views displayed through application routes -->
<script src="js/libs/angular-route.js"></script>
<!-- Load angularjs-resource, which allows us to interact with REST resources as high level services -->
<script src="js/libs/angular-resource.js"></script>
<!-- Load the controllers for our app -->
<script src="js/controllers/MemberCtrl.js"></script>
<!-- Load the application wide JS, such as route definitions -->
<script src="js/app.js"></script>
<!-- Load the services we have defined for the application, particularly the REST services -->
<script src="js/services/MemberSrv.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<div ng-controller="MembersCtrl">
<h1 align="center">International Bank Application</h1>
<div>
<p>You have successfully connected to the Application.</p>
</div>
<form name="regForm" ng-submit="register()">
<h2>Member Registration</h2>
<fieldset>
<legend>Register a member:</legend>
<div>
<label for="name">Name:</label>
<input type="text" name="name" id="name" ng-model="newPerson.name" placeholder="Your Name" required
autofocus/>
</div>
<div>
<label for="lname">Lname:</label>
<input type="text" name="lname" id="lname" ng-model="newPerson.lname" placeholder="Your Lastname"
required/>
</div>
<div>
<label for="dob">Date</label>
<input type="date" name="dob" id="dob" ng-model="newPerson.dob" placeholder="Your Date" required/>
</div>
<ul ng-hide="!successMessages" class="success">
<li ng-repeat="message in successMessages">{{message}}</li>
</ul>
<ul ng-hide="!errorMessages" class="error">
<li ng-repeat="message in errorMessages">{{message}}</li>
</ul>
<div>
<input type="submit" ng-disabled="regForm.$invalid" id="register" value="Register"/>
<input type="button" ng-click="reset()" name="cancel"
id="cancel" value="Cancel"/>
</div>
</fieldset>
</form>
<h2>Persons</h2>
<em ng-show="persons.length == 0">No registered members.</em>
<table ng-hide="persons.length == 0" class="simpletablestyle">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Lname</th>
<th>Date</th>
<th>REST URL</th>
</tr>
</thead>
<tr ng-repeat="person in persons | orderBy:orderBy">
<td>{{person.id}}</td>
<td>{{person.name}}</td>
<td>{{person.lname}}</td>
<td>{{person.dob}}</td>
<td>details-{{person.id}}
</td>
</table>
<div>
REST URL for all members: /rest/members
</div>
<div>
<input type="button" ng-click="refresh()" name="refresh"
id="refresh" value="Refresh"/>
</div>
</div>
Change controller: MembersCtrl to controller: 'MembersCtrl' in $routeProvider config
I am trying to learn angular.js and I want to load a form html through angular-route with a template.
I think I set up everything correctly, but the html form won't load on the url that I set on config. And the other config url I set up for testing won't work either.
Here is the code
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/style.css">
</head>
<body ng-app="EventPlanner">
<div ng-view></div>
</body>
</html>
<script type="text/javascript" src="/bower_components/angular/angular.min.js"></script>
<script type="text/javascript" src="/bower_components/angular-route/angular-route.min.js"></script>
<script type="text/javascript" src="/js/angular/ng_config.js"></script>
<script type="text/javascript" src="/js/angular/ng_controller.js"></script>
ng_config.js
angular.module("EventPlanner", ["ngRoute"])
.config(["$routeProvider", function($routeProvider){
$routeProvider.when("/", {
templateUrl: "template/register.html"
})
.when("/make_plan", {
template: "<h1>make plans</h1>"
});
}]);
ng_controller.js
angular.module("EventPlanner", [])
.controller("registerControl", [function(){
var self = this;
self.submit = function(){
location.href = "#/make_plan";
};
}]);
register.html
<div class="main container">
<div class="row" ng-controller="registerControl as regi">
<form ng-submit="regi.submit()" name="regiForm" class="register col-xs-12">
<label class="col-xs-12" for="name">
<span class="col-xs-2">Name</span>
<input ng-model="regi.username" class="col-xs-5" type="text" id="name" name="name" required>
<span class="col-xs-5" ng-show="regiForm.name.$error.required">This feild is required</span>
</label>
<label class="col-xs-12" for="email">
<span class="col-xs-2">Email</span><input ng-model="regi.email" class="col-xs-5" type="email" id="email" name="email" required>
<span class="col-xs-5" ng-show="regiForm.email.$error.required">This feild is required</span>
</label>
<label class="col-xs-12" for="birthday">
<span class="col-xs-2">Birthday</span><input ng-model="regi.birthday" class="col-xs-5" type="date" id="birthday">
</label>
<label class="col-xs-12" for="password">
<span class="col-xs-2">Password</span>
<input ng-model="regi.password" class="col-xs-5" type="password" id="password" name="password"
ng-pattern="/^(?=.*[0-9])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]{6,16}$/" ng-minlength="6" ng-maxlength="16" required>
</label>
<ul class="col-xs-7">
<li class="col-xs-12" ng-show="regiForm.password.$error.pattern">Must contain one lower & uppercase letter, and one non-alpha character (a number or a symbol.)</li>
<li class="col-xs-12" ng-show="regiForm.password.$error.minlength">Password Must be more than 5 characters</li>
<li class="col-xs-12" ng-show="regiForm.password.$error.maxlength">Password Must be less than 20 characters</li>
<li class="col-xs-12" ng-show="regiForm.name.$dirty && regiForm.name.$error.required">Please enter name
</li>
</ul>
<div class="col-xs-7 no-padding">
<button type="submit" ng-disabled="regiForm.$invalid" class="btn">Submit</button>
</div>
</form>
</div>
I have been looking at the code over and over for past few days, I cannot figure out what I did wrong.
Please help.
Thank you.
You have an error in your code.
ng_config.js
angular.module("EventPlanner", ["ngRoute"]) // correct!
.config(["$routeProvider", function($routeProvider){
$routeProvider.when("/", {
templateUrl: "template/register.html"
})
.when("/make_plan", {
template: "<h1>make plans</h1>"
});
}]);
The above is correct, you are defining a new module 'EventPlanner' and defining an array of dependencies.
ng_controller.js
angular.module("EventPlanner", []) // incorrect!!
.controller("registerControl", [function(){
var self = this;
self.submit = function(){
location.href = "#/make_plan";
};
}]);
The above is incorrect. You do not need to pass an empty array anymore as you have already created your module 'EventPlanner'.
What is actually happening above is you are redefining the module 'EventPlanner' and overwriting your previous declaration.
Change ng_controller.js to the following:
angular.module("EventPlanner") // fixed
.controller("registerControl", [function(){
var self = this;
self.submit = function(){
location.href = "#/make_plan";
};
}]);
Now, when ng_controller.js is parsed, it tells angular that it wishes to create a 'registerController' for a previously defined module called 'EventPlanner'. Hope that makes sense.
So, I have this form, made using AngularJS here, which basically lets me create a purchase object to send to a server, i.e, it lets me select a store where I bought some items, set a "date of purchase" (just a text field for now), and add those items to the object I'm gonna send.
After the submit button it is shown how the model I'm going to send will look like, showing the id of the store, the "datetime", and an array of items.
My question is: Is there a way of doing this form using angular-formly only?
The question arises because I've been reading formly's docs and I haven't figured out how to make it create such a dynamic model as this form does, i.e., with a variable-length array of items of the purchase, or if it is at all possible.
Thanks in advance for any clue you can give me to answer this question :)
The code for the form is as follows:
(function(){
var app = angular.module('test', []);
})();
The html page:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.js"></script>
<script src="inab.js"></script>
<script src="PurchaseCtrl.js"></script>
</head>
<body ng-app="test">
<div ng-controller="PurchaseCtrl" class="col-md-4">
<h2>Purchase</h2>
<div class="panel panel-default">
<div class="panel-heading">Title</div>
<div class="panel-body">
<div class="form-group">
<label>Store</label>
<select class="form-control" ng-model="model.store">
<option ng-repeat="store in stores" value="{{store.id}}">{{store.name}}</option>
</select>
</div>
<div class="form-group">
<label>date-time</label>
<input class="form-control" type="text" ng-model="model.datetime"/>
</div>
<div ng-repeat="item in items">
<div class="form-group">
<div class="col-sm-2">
<label>{{item.label}}</label>
</div>
<div class="col-sm-8">
<input class="form-control" type="text" ng-model="item.nome" />
</div>
<div class="col-sm-2">
<button type="submit" class="btn btn-alert submit-button col-md-2" ng-click="removeItem()">remove item</button>
</div>
</div>
</div>
<button ng-click="addItem()">Add item</button>
</div>
</div>
<button type="submit" class="btn btn-primary submit-button" ng-click="onSubmit()">Submit</button>
<pre>{{model | json}}</pre>
</div>
</body>
</html>
The controller:
(function(){
angular.module('test').controller('PurchaseCtrl', ['$scope', function(scope){
scope.stores = [{id: 1, name:'Store 1'}, {id: 2, name: 'Store 2'}];
scope.items = [];
scope.datetime = '';
scope.store = '';
var i = 0;
scope.model = {
store: scope.store,
datetime: scope.datetime,
items: scope.items
};
scope.addItem = function(){
scope.items.push({label: 'algo' + (i++), nome:''});
}
scope.removeItem = function(){
scope.items.splice(scope.items.length - 1);
}
scope.onSubmit = function(){
console.log(scope.model);
}
}]);
})();
As #Satej commented, it was with repeated sections. Thanks :)
Okay so I have this problem where I have to hide the total amount of movies found in a search with the rotten tomatoes api. Every time I type in a query, I get a repeat of the same header with each different movie that appears. I need to only repeat it at the top. Here is an image of what is happening since I can't do it in JSFiddle.
Here is my HTML code:
<html ng-app="demoApp">
<head>
<title>demo</title>
<script src="angular.min.js"></script>
<script src="search.js"></script>
</head>
<body ng-controller="moviesController">
<label for="q">Search Text</label>
<input type="text" id="q" ng-model="data.q" ng-model-options="{debounce: 500}"/>
<label for="page_limit">Page Size</label>
<input type="text" id="page_limit" ng-model="data.page_limit" ng-model-options="{debounce: 500}"/>
<label for="page">Page Number</label>
<input type="text" id="page" ng-model="data.page" ng-model-options="{debounce: 500}"/>
<div class="movie" ng-repeat="movie in movies">
<h1>Total movies: {{totalMovies}}</h1>
<div>
<img src="{{movie.posters.thumbnail}}" />
<h2>{{movie.title}}</h2>
</div>
<div>
<p>{{movie.synopsis}}</p>
<dl>
<dt>Rating</dt>
<dd>{{movie.mpaa_rating}}</dd>
<dt>Year</dt>
<dd>{{movie.year}}</dd>
<dt>Critics Score</dt>
<dd>{{movie.ratings.critics_score}}</dd>
<dt>Audience Score</dt>
<dd>{{movie.ratings.audience_score}}</dd>
<dt>Theater Release Date</dt>
<dd>{{movie.release_dates.theater}}</dd>
<dt>DVD Release Date</dt>
<dd>{{movie.release_dates.dvd}}</dd>
</dl>
</div>
</div>
</body>
</html>
Here is my angularJS code
angular.module('demoApp', [])
.constant('apiKey', 'removed for security')
.constant('apiUrl', 'http://api.rottentomatoes.com/api/public/v1.0/movies.json')
.controller('moviesController', function ($scope, $http, apiUrl, apiKey) {
$scope.data = {}
$scope.$watchGroup(['data.q', 'data.page_limit', 'data.page'], function () {
$http.jsonp(apiUrl, {
params: {
q: $scope.data.q,
page_limit: $scope.data.page_limit,
page: $scope.data.page,
apikey: apiKey,
callback: 'JSON_CALLBACK'
}
}).then(function (response) {
$scope.movies = response.data.movies;
//Call total movies
$scope.totalMovies = response.data.total;
});
});
});
Just check the index:
<h1 ng-if="$index == 0">Total movies: {{totalMovies}}</h1>
Move the total movie heading outside of the ngRepeat.
<h1>Total movies: {{totalMovies}}</h1>
<div class="movie" ng-repeat="movie in movies">
<!-- movie stuff -->
I have a php session variable set in index.php file. Using ng-init I am assigning that session value to a variable so that I can use in my angularjs controller file.
This is my index.php file
<body ng-app="myApp">
<div ng-controller="restaurantController" ng-init="total=0;something='<?php echo $_SESSION['rname'] ?>'" class="container">
<div class="col l4 s4 container">
<label>Search</label> <input type="text" ng-model="search.name">
</div>
<div ng-repeat="item in items | filter:search" class="container">
<h3>{{item.name}}</h3>
<p>category:{{item.category}}</p>
<p>price:INR {{item.price}} /-</p>
<br/>
<button ng-hide="item.added" ng-click="process(item)">Add</button>
<button ng-show="item.added" class="ng-cloak">Remove</button>
</div>
<h1>Total:<span ng-model="total">{{total}}</span></h1>
</div>
<script src="../angular/app.js"></script>
<script src="../angular/restaurantController.js"></script>
<script src="../materialize/js/materialize.min.js"></script>
</body>
Here the variable something is assigned to a php session variable.
But I am getting undefined when I use $scope.something in controller file.
This is my controller file
var myApp = angular.module('myApp',[]);
myApp.controller('restaurantController',['$scope','$http', function($scope, $http){
$http.get($scope.something+'.json').success(function (data){
$scope.items = data;
});
$scope.process = function(item){
$scope.total = parseInt($scope.total) + parseInt(item.price);
item.added=true;
}
}]);
The value of $scope.something is undefined in controller file but in php file I am getting the correct value.
<body ng-app="myApp" ng-init="total=0;something='<?php echo $_SESSION['rname'] ?>'">
<div ng-controller="restaurantController" class="container">
<div class="col l4 s4 container">
<label>Search</label> <input type="text" ng-model="search.name">
</div>
<div ng-repeat="item in items | filter:search" class="container">
<h3>{{item.name}}</h3>
<p>category:{{item.category}}</p>
<p>price:INR {{item.price}} /-</p>
<br/>
<button ng-hide="item.added" ng-click="process(item)">Add</button>
<button ng-show="item.added" class="ng-cloak">Remove</button>
</div>
<h1>Total:<span ng-model="total">{{total}}</span></h1>
</div>
<script src="../angular/app.js"></script>
<script src="../angular/restaurantController.js"></script>
<script src="../materialize/js/materialize.min.js"></script>
</body>
Got the solution. just had to change the position of ng-init so that the variables can e initialized as soon as the page loads.