Syncronization with angularjs $http function - angularjs

I am new to angularjs and I have a very small app that loads contacts from my server. The code snippet here is the complete app.js.
The problem is that I can't figure out how to do the server call with sync. In the code snippet, when I refresh the page, alert 3 is displayed, then alert 2, and then finally alert 4. The function is immediately returning since the server http call take some time to do. So what I get in the browser is a display of the 2 test item in the array "contacts". Alert 4 finally comes along, but it is too late. Any help would be appreciated.
var module = angular.module('app', []);
module.service('ContactService', function ($http) {
//contacts array to hold list of all contacts - 2 entries for test
//var $contacts = [];
var contacts = [
{
id: 0,
'First_Name': 'Harmon',
'Last_Name': 'Adams',
'Home_Phone': '123-2343-44'
},
{
id: 1,
'First_Name': 'Sam',
'Last_Name': 'Spade',
'Home_Phone': '123-2343-44'
}
];
// returns the contacts list
this.list = function () {
// var contacts = [];
$http.post('http://localhost/Contacts7/GetData.php', {'cat' : 'Friends'}).
success(function(data) {
contacts = data.datarecords;
alert('4 - within $post - '+contacts);
}).
error(function(data, status){
alert('error!');
});
alert('3 - before return - '+contacts);
return contacts;
}
});
module.controller('ContactController', function ($scope, ContactService ) {
$scope.contacts = ContactService.list();
alert('2 - after list - '+ $scope.contacts);
});
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Contact Dialer </title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div ng-app="app" ng-controller="ContactController">
<div class="container" >
<div class="row row-centered">
<div class="col-md-2 button-row col-centered">
<button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Favorites')">Favorites</button>
</div>
<div class="col-md-2 button-row col-centered">
<button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Friends')">Friends</button>
</div>
<div class="col-md-2 button-row col-centered">
<button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Loose Friends')">Loose Friends</button>
</div>
<div class="col-md-2 button-row col-centered">
<button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Loose_Loose Friends')">Loose-Loose Friends</button>
</div>
<div class="col-md-2 button-row col-centered">
<button type="button" class="btn btn-Primary btn-l btn-block" ng-click="GetByCat('Business')">Business</button>
</div>
<div class="col-md-2 button-row">
</div>
</div>
{{xxx}}
<table class='table table-striped table-bordered'>
<th class = 'text-center'>Name</th>
<th class = 'text-center'>Home Phone</th>
<th class = 'text-center'>Mobile Phone</th>
<th class = 'text-center'>Bus. Phone</th>
</tr>
<tr ng-repeat='contact in contacts'>
<th class = 'text-center' >{{contact.Last_Name}}, {{contact.First_Name}}</th>
<td class = 'text-center'>{{contact.Home_Phone}}</td>
<td class = 'text-center'>{{contact.Mobile_Phone}}</td>
<td class = 'text-center'>{{contact.Business_Phone}}</td>
</tr>
</table></div>
</div>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="js/underscore-min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/angular.min.js"></script>
<script src="js/angular-route.min.js"></script>
<script src="js/app.js"></script>
</body>
</h

You can't return contacts from your service because contacts is going to be determined asynchronously. Instead you need to return a promise for the contacts, which you can use to populate your controller's contacts when they are done being retrieved.
Service:
module.service('ContactService', ['$http', function ($http) {
return {
list: function () {
return $http.post('http://localhost/Contacts7/GetData.php',
{'cat' : 'Friends'})
.then(function (response) {
return response.data.datarecords;
})
.catch(function (error) {
throw new Error("Failed to retrieve contacts!");
});
}
};
}]);
Note You may have noticed that I changed the first line from using the magic dependency injection style to using the array-style dependency injection. This is just my personal preference (because I consider the magic DI style to be a bad idea), and not something that you have to do. The same applies to the code below.
Controller:
module.controller('ContactController', ['$scope', 'ContactService',
function ($scope, ContactService ) {
$scope.contacts = [];
ContactService.list()
.then(function (contacts) {
$scope.contacts = contacts;
alert('2 - after list - '+ $scope.contacts);
});
}]);

Don't return contacts object from outside ajax.
It should be return contacts object from its success callback.
// returns the contacts list
this.list = function () {
// var contacts = [];
$http.post('http://localhost/Contacts7/GetData.php', {'cat' : 'Friends'}).then(
//success call back
function(data) {
contacts = data.datarecords;
alert('4 - within $post - '+contacts);
return contacts;
},
//error call back
function(data, status){
//error handling can be done here
alert('error!');
return;
});
Hope this may help full to you.

Related

Implementing a Session Factory

I have the following application implementing a Session Service that interacts with the HTML5 window.sessionStorage object. It works well. I'm trying to do the same as the service using a Session Factory but it doesn't work.
My application has the following files:
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Services and Factories</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body ng-controller="sessionController as vm">
<div class="container">
<h1>Services and Factories</h1>
<div class="form-group row">
<div class="col-sm-4">
<label>Name</label>
</div>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="vm.model.name">
</div>
</div>
<div class="form-group row">
<div class="col-sm-4">
<label>Nickname</label>
</div>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="vm.model.nickname">
</div>
</div>
<div class="form-group row">
<div class="col-sm-8 col-sm-offset-4">
<input ng-click="vm.setServiceSession()" type="button" class="btn btn-primary" value="Save with Service" />
<input ng-click="vm.getServiceSession()" type="button" class="btn btn-default" value="Retrieve from Service" />
<input ng-click="vm.clearServiceSession()" type="button" class="btn btn-default" value="Clear from Service" />
</div>
</div>
<pre>{{vm.model | json}}</pre>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<script src="app/app.js"></script>
<script src="app/sessionController.js"></script>
<script src="app/sessionService.js"></script>
</body>
</html>
app/app.js
angular.module('app', []);
app/sessionController.js
angular.module('app').controller('sessionController', ['sessionService', sessionController]);
function sessionController(sessionService) {
var vm = this;
vm.getServiceSession = function() {
vm.model = {
name: sessionService.get('name'),
nickname: sessionService.get('nickname'),
status: 'Retrieved by service on ' + new Date()
};
};
vm.setServiceSession = function() {
sessionService.save('name', vm.model.name);
sessionService.save('nickname', vm.model.nickname);
vm.getServiceSession();
};
vm.clearServiceSession = function() {
sessionService.clear();
vm.getServiceSession();
};
}
app/sessionService.js
angular.module('app').service('sessionService', ['$window', sessionService]);
function sessionService($window) {
this.save = save;
this.get = get;
this.clear = clear;
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key, value) {
return $window.sessionStorage.getItem(key);
}
function clear() {
$window.sessionStorage.clear();
}
}
The Session Service works well. Then I try to add a Session Factory to do the same as the Session Service, but everything stops working. I add the following file:
app/sessionFactory.js
angular.module('app').factory('sessionFactory', ['$window', sessionFactory]);
function sessionFactory($window) {
return {
save: save,
get: get,
clear: clear
};
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key, value) {
return $window.sessionStorage.getItem(key);
}
function clear() {
$window.sessionStorage.clear();
}
}
And I modify:
index.html (adding 3 new buttons to for the Factory and the sessionFactory script)
<div class="form-group row">
<div class="col-sm-8 col-sm-offset-4">
<input type="button" class="btn btn-primary" value="Save with Factory" ng-click="vm.setFactorySession()" />
<input type="button" class="btn btn-default" value="Retrieve from Factory" ng-click="vm.getFactorySession()" />
<input type="button" class="btn btn-default" value="Clear from Factory" ng-click="vm.clearFactorySession()" />
</div>
</div>
...
<script src="app/sessionFactory.js"></script>
sessionController.js (adding the sessionFactory)
angular.module('app').controller('sessionController', ['sessionService', 'sessionFactory', sessionController]);
function sessionController(sessionService, sessionFactory) {
...
var mySessionFactory = new sessionFactory();
vm.getFactorySession = getFactorySession;
vm.setFactorySession = setFactorySession;
vm.clearFactorySession = clearFactorySession;
function getFactorySession() {
vm.model = {
name: mySessionFactory.get('name'),
nickname: mySessionFactory.get('nickname'),
status: 'Retrieved by Factory on ' + new Date()
};
}
function setFactorySession() {
mySessionFactory.save('name', vm.model.name);
mySessionFactory.save('nickname', vm.model.nickname);
getFactorySession();
}
function clearFactorySession() {
mySessionFactory.clear();
getFactorySession();
}
}
As factories and services are singletone you don't need to use new. Just remove that and do the same.
remove:
var mySessionFactory = new sessionFactory();
All the best.
You don't need to use new sessionFactory() when using a factory.
Instead, use sessionFactory.get('name') and it will work.
This is the main difference between service and factory.
Check this blog post for more insights.

ng-if not really as intended

I'm trying to make a page print with Angular, using ng-if.
$scope.onBtnPrintClicked = function(journal, date) {
$scope.printTransaction = false;
$scope.current = new Date();
window.print()
};
$scope.onBtnPrintTransactionClicked = function(journal, date) {
$scope.printTransaction = true;
$scope.current = new Date();
window.print()
};
<button ng-click="onBtnPrintTransactionClicked(journal, selected.date)" class="btn btn-default btn-sm"><i class="fa fa-print"></i> Print</button>
<button ng-click="onBtnPrintClicked(journal, selected.date)" class="btn btn-default btn-sm"><i class="fa fa-print"></i>Print 2</button>
<section ng-if="printTransaction" class="printable journal-container">
<h1>PRINT</h1>
</section>
<section ng-if="!printTransaction" class="printable journal-container">
<div class="row">
<div class="col-sm-12">PRINT2</div>
</div>
</section>
But when I try to click print/print 2 it's showing different page/content.
What could be the problem?
From what I could understand from your question is that you're trying to print the current page, however the changes performed by your functions aren't completely load yet, so you could use setTimeout to make a little delay, as below:
(function() {
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope'];
function MainCtrl($scope) {
$scope.printTransaction = true;
$scope.onBtnPrintClicked = function(journal, date) {
$scope.printTransaction = false;
$scope.current = new Date();
setTimeout(function() {
window.print();
}, 500);
};
$scope.onBtnPrintTransactionClicked = function(journal, date) {
$scope.printTransaction = true;
$scope.current = new Date();
setTimeout(function() {
window.print();
}, 500);
};
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
</head>
<body ng-controller="MainCtrl">
<button ng-click="onBtnPrintTransactionClicked(journal, selected.date)" class="btn btn-default btn-sm"><i class="fa fa-print"></i> Print</button>
<button ng-click="onBtnPrintClicked(journal, selected.date)" class="btn btn-default btn-sm"><i class="fa fa-print"></i> Print 2</button>
<section ng-if="printTransaction" class="printable journal-container">
<h1>PRINT</h1>
</section>
<section ng-if="!printTransaction" class="printable journal-container">
<div class="row">
<div class="col-sm-12">PRINT2</div>
</div>
</section>
</body>
</html>
Note: I don't know if these are your real functions, but you could simplify it and do it all in a single function.

Submit button needs to be clicked twice to call onSuccess Adaptor function in IBM Mobile First

I am using AngularJS in a IBM MobileFirst Platform Foundation app. I have a login form and when I click the Login button it collects some data and passes it to adapter invoke function. If it is successful it never calls success loginSuccess function. I need to click Login button twice so that the success function is called.
Why do I need to click button twice?
app.js
var app = angular.module('myApp', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/login');
$stateProvider.state('login', {
url: '/login',
templateUrl: 'view/login.html',
controller: 'loginController'
});
});
login.js
app.controller('loginController', function($scope) {
$scope.login = function(usrName, pass) {
var usrName = angular.element('#usrName').val();
var pass = angular.element('#pass').val();
console.log("Variable values: " + usrName + " : " + pass);
$scope.loginProcedure = {
adapter: 'SQL',
procedure: 'login',
parameters: [usrName, pass]
};
WL.Client.invokeProcedure($scope.loginProcedure, {
onSuccess: $scope.loginSuccess,
onFailure: $scope.loginFailure
});
$scope.loginSuccess = function(data) {
$scope.data = data;
$scope.resultSet = data.resultSet;
console.log('success: ' + JSON.stringify($scope.data + " : " + $scope.resultSet));
};
$scope.loginFailure = function() {
console.log('failed');
};
}
});
SQL-impl.js
/*
* Licensed Materials - Property of IBM
* 5725-I43 (C) Copyright IBM Corp. 2011, 2013. All Rights Reserved.
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/************************************************************************
* Implementation code for procedure - 'procedure1'
*
*
* #return - invocationResult
*/
var loginStatement = WL.Server.createSQLStatement("select usrname,password from jay1 where usrname = ? and password=? ");
function login(usr, pass) {
return WL.Server.invokeSQLStatement({
preparedStatement: loginStatement,
parameters: [usr, pass]
});
}
/************************************************************************
* Implementation code for procedure - 'procedure2'
*
*
* #return - invocationResult
*/
function procedure2(param) {
return WL.Server.invokeSQLStoredProcedure({
procedure: "storedProcedure2",
parameters: [param]
});
}
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>AB</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0">
<!--
<link rel="shortcut icon" href="images/favicon.png">
<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
-->
<link rel="stylesheet" href="css/main.css" />
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/bootstrap-responsive.min.css" />
<script>
window.$ = window.jQuery = WLJQ;
</script>
</head>
<body ng-app="myApp">
<!--application UI goes here-->
<div id="view" ui-view></div>
<script src="js/initOptions.js"></script>
<script src="js/main.js"></script>
<script src="js/messages.js"></script>
<script src="library/jquery.min.js"></script>
<script src="library/angular.1.4.9.js"></script>
<script src="library/angular-ui-router.min.js"></script>
<script src="library/bootstrap.min.js"></script>
<script src="controller/app.js"></script>
<script src="controller/login.js"></script>
</body>
</html>
login.html
<div ng-controller="loginController" class="col-xs-12 col-sm-6 col-md-4 center-block" id="lgBlock">
<!-- Login Box Start -->
<div class="panel panel-primary">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-group" name="lgForm">
<input type="text" class="form-control" id="usrName" required />
<input type="password" class="form-control" id="pass" required />
<input type="submit" class="btn btn-primary btn-block" id="submit" value="Login" ng-click="login()" />
</form>
</div>
</div>
<!-- Login Box End -->
<!-- error Modal start -->
<div class="modal" role="modal" id="errorPopup">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">Error</div>
<div class="modal-body"></div>
</div>
</div>
</div>
<!-- error Modal End -->
</div>
Which is correct way to parse JSON data using angularJS $scope?
1) $scope.data = data; $scope.resultSet = data.resultSet;
2) $scope.data = data; $scope.resultSet = $scope.data.resultSet;
You should take advantage of AngularJS two-way binding an update your login controller as follows:
login.js
app.controller('loginController', function($scope) {
$scope.login = function() {
// TODO: if block to validate user input i.e., username and password
$scope.loginProcedure = {
adapter: 'SQL',
procedure: 'login',
parameters: [$scope.username, $scope.password]
};
WL.Client.invokeProcedure($scope.loginProcedure, {
onSuccess: $scope.loginSuccess,
onFailure: $scope.loginFailure
});
console.log($scope.loginProcedure);
$scope.loginSuccess = function(data) {
$scope.data = data;
// resultSet is part of data so you don't need to refrences
// you can use $scope.data.resultSet to access resultSet
console.log('success: ' + JSON.stringify($scope.data + " : " + $scope.data.resultSet));
};
$scope.loginFailure = function() {
console.log('failed');
};
}
});
You should also update your view to declare the binding for username and password
login.html
<div ng-controller="loginController" class="col-xs-12 col-sm-6 col-md-4 center-block" id="lgBlock">
<!-- Login Box Start -->
<div class="panel panel-primary">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-group" name="lgForm">
<input type="text" class="form-control" id="usrName" ng-model="username" required />
<input type="password" class="form-control" id="pass" ng-model="password" required />
<input type="submit" class="btn btn-primary btn-block" id="submit" value="Login" ng-click="login()" />
</form>
</div>
</div>
<!-- Login Box End -->
<!-- error Modal start -->
<div class="modal" role="modal" id="errorPopup">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">Error</div>
<div class="modal-body"></div>
</div>
</div>
</div>
<!-- error Modal End -->
</div>
The way you pass data to the $scope is totally up to you and your needs. My suggestion is to determine what you need and only bind that to the $scope for example if you only need data.resultSet then you should do $scope.resultSet. On the other hand, if you need complete access to the data object then you should bind data to the $scope and the you can still access the resultSet from there i.e., $scope.data.resultSet
Suggestions:
Only bind the things you need to reference in the view to the $scope for example you don't need access to the loginSuccess nor loginFailure in the view and you are only using those two functions once, so I recommend you update your loginController as follows:
app.controller('loginController', function($scope) {
$scope.login = function() {
// TODO: if block to validate user input i.e., username and password
$scope.loginProcedure = {
adapter: 'SQL',
procedure: 'login',
parameters: [$scope.username, $scope.password]
};
WL.Client.invokeProcedure($scope.loginProcedure, {
onSuccess: function(data) {
$scope.data = data;
// resultSet is part of data so you don't need to refrences
// you can use $scope.data.resultSet to access resultSet
console.log('success: ' + JSON.stringify($scope.data + " : " + $scope.data.resultSet));
},
onFailure: function() {
console.log('failed');
}
});
}
});

Linking one controller to another to call service on ng-click

I have two templates with respective controllers and service files. One template's(fleetListTemplate) controller(fleetListController) loads data from its service file(fleetService) and displays in its view(fleetListTemplate).
When this happens, and I click on one of the loaded data from fleetService, I should link fleetListController to fleetSummaryController to get data from its service file (fleetSummaryService) and display in fleetSummaryTemplate view.
Can someone please help me with the coding? Thank you.
The following are the respective modules, templates, controllers and service files.
fleetListModule
"use strict";
angular.module("fleetListModule", []);
fleetListTemplate
<div class="panel1 panel-primary">
<div class="panel-heading" align="center">TRUCKS</div>
<table class="table table-bordered table-condensed table-striped">
<tr>
<th>TruckID</th>
<th>Status</th>
<th>Dest.</th>
<th>Alerts</th>
</tr>
<tr ng-repeat="truck in trucks" ng-click="summaryData()">
<td>{{truck.truckID}}</td>
<td>{{truck.status}}</td>
<td>{{truck.destination}}</td>
<td>{{truck.alerts}}</td>
</tr>
</table>
</div>
fleetListController
"use strict";
angular.module("fleetListModule").controller("fleetListController",
['$scope', 'fleetsService',
function ($scope, fleetsService) {
$scope.trucks = fleetsService.getTrucks();
$scope.summaryData = function () {
$rootScope.$broadcast('obtainSummary');
}
}]);
fleetSummaryModule
"use strict";
angular.module("fleetSummaryModule", []);
fleetSummaryTemplate
<div class="panel2 panel-primary">
<div class="panel-heading">Summary</div>
<table class="table table-bordered table-condensed table-striped">
<tr ng-repeat="summary in truckSummary">
<td>Truck ID: {{summary.truckID}}</td>
<td>Trailer ID: {{summary.trailerID}}</td>
<td>Driver ID: {{summary.driverID}}</td>
<td>Truck Number: {{summary.truckNumber}}</td>
<td>Trailer Number: {{summary.trailerNumber}}</td>
<td>Insurance Due Date: {{summary.insuranceDueDate}}</td>
<td>Maintenance Due Date: {{summary.maintenanceDueDate}}</td>
</tr>
</table>
</div>
fleetSummaryController
"use strict";
angular.module("fleetSummaryModule").controller("fleetSummaryController",
['$scope', 'fleetSummaryService',
function ($scope, fleetSummaryService) {
$scope.$on('obtainSummary', function (event, args) {
$scope.truckSummary = fleetSummaryService.getSummary();
})
}]);
fleetSummaryService
"use strict";
angular.module("fleetSummaryModule").service("fleetSummaryService",
function () {
this.getSummary = function () {
return summary;
};
this.getSummary = function (truckID) {
for (var i = 0, len = truckSummary.length; i < len; i++) {
if (truckSummary[i].truckID === parseInt(truckID)) {
return truckSummary[i];
}
}
return {};
};
var truckSummary = [
{
truckID: 1,
trailerID: '123',
driverID: 'Alex123',
truckNumber: 'hyt 583',
trailerNumber: 'xyz213',
insuranceDueDate: '25-12-2015',
maintenanceDueDate: '31-12-2015'
},
{
truckID: 2,
trailerID: '456',
driverID: 'Alex123',
truckNumber: 'hyt 583',
trailerNumber: 'xyz213',
insuranceDueDate: '25-12-2015',
maintenanceDueDate: '31-12-2015'
},
{
truckID: 3,
trailerID: '789',
driverID: 'Alex123',
truckNumber: 'hyt 583',
trailerNumber: 'xyz213',
insuranceDueDate: '25-12-2015',
maintenanceDueDate: '31-12-2015'
}
];
});
This simple example show to you how to share data between 2 controllers "in one app"
using common service.
angular.module("app", []);
///controller1
angular.module("app").controller("controller1", function ($scope, service) {
$scope.lists = [
{ name: "maher" },
{ name: "Gaurav Ram" },
{ name: "Shaun Scovil" }
];
$scope.send = function () {
service.set("lists", $scope.lists); //set(key, value)
$scope.lists = []; //optional
}
});
///controller2
angular.module("app").controller("controller2", function ($scope, service) {
$scope.lists = [];
//get data from broadcast on the root
service.get("lists"); // get(key)
//set data
$scope.resive = function () {
if (angular.isUndefined($scope.broadcast)) {
$scope.alert = "No data to resive!";
} else {
$scope.alert = null;
$scope.lists = $scope.broadcast;
}
}
});
///service
angular.module("app").service("service", function ($rootScope) {
this.set = function (key, value) {
$rootScope.$broadcast(key, value);
}
this.get = function (key) {
$rootScope.$on(key, function (event, data) {
$rootScope.broadcast = data;
});
}
});
<!doctype html>
<html ng-app="app">
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div ng-controller="controller1" class="col-md-6 col-sm-6 col-xs-6">
<div class="page-header">
<h1>controller 1</h1>
</div>
<button ng-click="send()" class="btn btn-primary">Send</button>
<div class="clearfix"></div>
<br/>
<div class="alert alert-info" ng-if="lists.length == 0">Data <b>sent</b> to controller 2, click Resive button to get data</div>
<ul class="list-group">
<li ng-repeat="list in lists" class="list-group-item" ng-bind="list.name"></li>
</ul>
</div>
<div ng-controller="controller2" class="col-md-6 col-sm-6 col-xs-6">
<div class="page-header">
<h1>controller 2</h1>
</div>
<button ng-click="resive()" class="btn btn-success">Resive</button>
<div class="clearfix"></div>
<br />
<div class="alert alert-info" ng-bind="alert" ng-if="alert"></div>
<ul class="list-group">
<li ng-repeat="list in lists" class="list-group-item" ng-bind="list.name"></li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
</body>
</html>

Angular routing/path change and scope issues

I am new to AngularJS and I'm facing these issues :
I want to have a list of items (movies) and when I click on the image or on the title I want the path to be like #/movie/id. For that I tried using ngRoute and also tried path but I have faced errors in both, can you guide me which one is suitable for my case and how can I use it?
As you can see in the HTML code, I am trying to draw a search box but right now when the API runs and returns data the whole content of the ng-app is being replaced with the movie list, should I create a new scope for just the content I want to change, if so how and where?
Here is my code:
var movies = angular.module("movies", []);
movies.controller('movieController', function ($scope, $http) {
$http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json', {
params: {
limit : 16,
country : 'us',
apikey: 'rssd8z7pfw5t4nyd3cpszzzm',
callback: 'JSON_CALLBACK'
}
})
.success(function (data) {
$scope.movies = data.movies;
});
});
//added ngroute
var app = angular.module('movies', ['ngRoute']);
app.config(
function($routeProvider) {
$routeProvider.
when('/', {templateUrl:'/'}).
when('/movie/:id',
{
controller:UserView,
templateUrl: function(params){ return '/moviessssssss/' + params.id; }
}
).
otherwise({redirectTo:'/'});
}
);
app.controller('UserView', function($scope) {
$scope.movies = 'hereeeeeee!';
});
<html ng-app="movies">
<head>
<link rel="stylesheet" hrf="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" />
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.min.js"></script>
</head>
<body>
<div class="ng-scope">
Search : <input type="text" placeholder="filter for..." >
</div>
<div ng-view>
{{ message }}
<table ng-controller="movieController" class="ng-cloak">
<tr ng-repeat="movie in movies">
<td><a ng-href="#movie" ><img ng-src="{{ movie.posters.thumbnail}}"/></a></td>
<td><a ng-href="#movie" > {{ movie.title }} </a></td>
</tr>
</table>
</div>
For getting the links:
ng-href="{{'/#/movie/'+movie.id}}"
Then for getting the filter to work,
Put ng-model to your search box. And in your ng-repeat add | filter: ng-modelname
var movies = angular.module("movies", []);
movies.controller('movieController', function ($scope, $http) {
$http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json', {
params: {
limit : 16,
country : 'us',
apikey: 'rssd8z7pfw5t4nyd3cpszzzm',
callback: 'JSON_CALLBACK'
}
})
.success(function (data) {
$scope.movies = data.movies;
console.log($scope.movies);
});
});
<html ng-app="movies">
<head>
<link rel="stylesheet" hrf="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" />
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.min.js"></script>
</head>
<body>
<div class="ng-scope">
Search : <input type="text" placeholder="filter for..." ng-model="search">
</div>
<div ng-view>
{{ message }}
<table ng-controller="movieController" class="ng-cloak">
<tr ng-repeat="movie in movies | filter:search">
<td><a ng-href="{{'/#/movie/'+movie.id}}" ><img ng-src="{{ movie.posters.thumbnail}}"/></a></td>
<td><a ng-href="{{'/#/movie/'+movie.id}}" > {{ movie.title }} </a></td>
</tr>
</table>
</div>
TL;DR
Click Here to see a live plunker example.
in my example, i used bootstrap. remove if irrelevant
there is a TODO in my plunker - the server side movie filtering (when you type a something in the search field). you need to read more about it in developer.rottentomatoes.com
This is the routing configuration i would define:
movies.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/movies', {
templateUrl: 'movies.html',
controller: 'MoviesController',
resolve: {
movies: function($http) {
return $http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json', {
params: {
limit: 16,
country: 'us',
apikey: 'rssd8z7pfw5t4nyd3cpszzzm',
callback: 'JSON_CALLBACK'
}
});
}
}
})
.when('/movies/:id', {
templateUrl: 'movie.html',
controller: 'MovieController',
resolve: {
movie: function($http, $route) {
var id = $route.current.params.id;
return $http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/movies/' + id + '.json', {
params: {
limit: 1,
country: 'us',
apikey: 'rssd8z7pfw5t4nyd3cpszzzm',
callback: 'JSON_CALLBACK',
q: id
}
});
}
}
})
.otherwise({
redirectTo: '/movies'
});
});
/movies - a list of all movies
/movies/<movie id> - a specific details about the movie
NOTE - i used resolve to pre-fetch the json data (this is optional)
index.html
this is the main html code of your
<!DOCTYPE html>
<html ng-app="movies">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<script src="app.js"></script>
</head>
<body>
<div class="container">
<div ng-view></div>
</div>
</body>
</html>
movies.html
the view of the movie list.
we get the specific movie redirect by <a ng-href="#/movies/{{movie.id}}">
<input class="form-control" type="text" placeholder="Search ..." ng-model="search" >
<hr>
<table>
<tr ng-repeat="movie in movies | filter:search">
<td><a ng-href="#/movies/{{movie.id}}" ><img ng-src="{{ movie.posters.thumbnail}}"/></a></td>
<td><a ng-href="#/movies/{{movie.id}}"> {{ movie.title }} </a></td>
</tr>
</table>
movie.html
the view of the specific movie
<img class="img-responsive" ng-src="{{ movie.posters.detailed}}"/>
<h3>{{movie.title}} <small>{{movie.year}}</small></h3>
<p>{{movie.synopsis}}</p>
<hr>
<a class="btn btn-default" href="#/movies">Back</a>
<hr>
<pre>{{movie | json}}</pre>
MoviesController
the controller attached to the movies.html view
the $scope.$watch('search', is required to query the server for each input change you make. it's currently not working properly; rottentomatoes.com ignoring the q param. you need to read more about it in developer.rottentomatoes.com
movies.controller('MoviesController', function($scope, $http, movies) {
$scope.search = '';
$scope.$watch('search', function(newValue) {
// TODO: you need to request again the movie list from the server.
// Read more about the API here:
// http://developer.rottentomatoes.com/docs/read/json/v10/Movies_Search
$http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json', {
params: {
limit: 16,
country: 'us',
apikey: 'rssd8z7pfw5t4nyd3cpszzzm',
callback: 'JSON_CALLBACK',
q: newValue
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
.success(function(data) {
console.log(data);
$scope.movies = data.movies;
});
});
$scope.movies = movies.data.movies;
});
MovieController
the controller attached to the movie.html view
movies.controller('MovieController', function($scope, movie) {
$scope.movie = movie.data;
});
Live example - http://plnkr.co/edit/cJXTZWqBUXNTPinf7AoV?p=preview
For your first question do this:
<td><a ng-href="#/movie/{{movie.id}}"> {{movie.title}} </a></td>

Resources