angularJS good practise: how to create controllers for complex application? - angularjs

let assume I need to create a dashboard application that includes users, tasks and messages. I have a theoric knowledge of angularJS only, not real life application and I don't know exactly how to architect an angular application.
<html ng-app="myApp">
<head>
<script src="js/vendor/angular/angular.min.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div id="users" ng-controller="usersController"></div>
<div id="tasks" ng-controller="tasksController"></div>
<div id="messages" ng-controller="messagesController"></div>
</body>
</html>
and app.js
var myApp = angular.module('myApp', []);
myApp.controller('usersController', function($scope) {
$scope.users = [{id:1, username:'john'},{id:2, username:'jack'}];
});
myApp.controller('tasksController', function($scope) {
$scope.tasks = [];
$scope.addTask = function(userid, task) {
}
});
myApp.controller('messagesController', function($scope) {
$scope.messages = [];
$scope.addMessage = function(userid, message) {
}
});
I just cannot figure out how taskController can speak with usersContoller or Taskcontroller.
Or should I use something like
myApp.users = {};
myApp.tasks = {};
myApp.messages = {};
Or should I use a service for that ?
and finally how to watch for changes on that users, tasks and messages.

Related

Passing data from one route to another route

It must be able to pass data between route controllers. Like for example have an input field in one route where its contents will be displayed in the next route. I don't want it with $rootScope.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.name = "John Doe";
});
</script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
Name: <input ng-model="name">
<h1>You entered: {{name}}</h1>
Click to see this data to another page (route)
</div>
</body>
</html>
See This
RipTutorial -
Handling session storage through service using angularjs
app.factory('storageService', ['$rootScope', function($rootScope) {
return {
get: function(key) {
return sessionStorage.getItem(key);
},
save: function(key, data) {
sessionStorage.setItem(key, data);
}
};
}]);
app.controller('myCtrl',['storageService',function(storageService) {
// Save session data to storageService
storageService.save('key', 'value');
// Get saved session data from storageService
var sessionData = storageService.get('key');
});

$http get shortcut messing up program in AngularJS?

In the script below, I have posted a boiled down version of my code. It's essentially a simplified search engine.
The script loops through the $scope.list_of_fruit array, and filters it according to what is typed on a simple html input text box.
<script>
var app = angular.module("myapp",[]);
app.controller("usercontroller", function($scope){
$http
.get("test.php")
.then(function (response) {
$scope.myData = response.data.records;
});
$scope.list_of_fruit = ["apple", "banana", "pear", "kiwi"];
$scope.complete = function(boxtext){
var output = [];
angular.forEach($scope.list_of_fruit, function(fruit){
if(fruit.toLowerCase().indexOf(boxtext.toLowerCase()) == 0)
{
output.push(fruit);
}
});
$scope.filteredfruit = output;
}
});
</script>
This works fine and dandy, but when I paste that http get request up top, that is completely unrelated to that $scope.complete loop, the $scope.complete loop just stops working.
Am I missing something obvious?
app.controller("usercontroller", function($scope){
You don't have $http defined, so you are probably getting an javascript error.
Add $http to the function parameters:
app.controller("usercontroller", function($scope, $http){
I created a snippet and this appears to work now
var app = angular.module('myApp', []);
app.controller("usercontroller", function($scope, $http){
$http
.get("https://jsonplaceholder.typicode.com/posts")
.then(function (response) {
$scope.myData = response.data.records;
});
$scope.list_of_fruit = ["apple", "banana", "pear", "kiwi"];
$scope.complete = function(boxtext){
console.log(boxtext);
var output = [];
angular.forEach($scope.list_of_fruit, function(fruit){
if(fruit.toLowerCase().indexOf(boxtext.toLowerCase()) == 0)
{
output.push(fruit);
}
});
$scope.filteredfruit = output;
}
});
<!DOCTYPE html>
<html ng-app='myApp'>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://rawgit.com/angular/bower-angular/master/angular.min.js"></script>
<div ng-controller="usercontroller as vm">
{{list_of_fruit}}
{{filteredfruit}}
<input type="text" ng-model="search"/>
<button ng-click="complete(search)">Do something</button>
</div>
</body>
</html>

AngularJS overlaps http.get results and limits them to 10 per page

This happens to be my first angularJS application that fetches data from newsapi and displays all the result in an infinite scrolling pattern.
I am getting data but not as expected, the new results overlap the previous ones and limits to 10 per page.
please advice if i am doing something wrong.
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js">
</script>
<body>
<div class="w3-container" ng-app="myApp" ng-controller="myCtrl">
<p>Today's News:</p>
<div class="w3-card-4" style="width:100px margin:20px" ng-repeat="x in
source">
<img src="{{x.urlToImage}}" style="width:100%">
<div class="w3-container w3-center">
<h2>{{x.title}}</h2>
</div>
</div><br><br>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
var websites = ["the-times-of-india", "google-news", "bbc-news", "mirror",
"reuters", "the-hindu", "the-new-york-times", "the-wall-street-journal"];
for(var i=0; i<websites.length;i++){
$http.get("https://newsapi.org/v1/articles?source=" +websites[i]
+"&apiKey=f483fa2a3f714981afbee1a1996545b4")
.then(function(response) {
$scope.source = response.data.articles;
});
}
});
</script>
</body>
</html>
You are overwriting $scope.source in each loop over the sources. If you need to get all sources you can push it to an array of sources:
app.controller('myCtrl', function($scope, $http) {
var websites = ["the-times-of-india", "google-news", "bbc-news", "mirror",
"reuters", "the-hindu", "the-new-york-times", "the-wall-street-journal"];
$scope.sources=[];
for(var i=0; i<websites.length;i++){
$http.get("https://newsapi.org/v1/articles?source=" +websites[i]
+"&apiKey=f483fa2a3f714981afbee1a1996545b4")
.then(function(response) {
$scope.sources.push(response.data.articles);
});
}
})
Then, you can use the $scope.sources and iterate over each source.
If you need all articles merged in one array, you can use the concat() method for arrays:
app.controller('myCtrl', function($scope, $http) {
var websites = ["the-times-of-india", "google-news", "bbc-news", "mirror",
"reuters", "the-hindu", "the-new-york-times", "the-wall-street-journal"];
$scope.source=[];
for(var i=0; i<websites.length;i++){
$http.get("https://newsapi.org/v1/articles?source=" +websites[i]
+"&apiKey=f483fa2a3f714981afbee1a1996545b4")
.then(function(response) {
if (response.data.articles){
$scope.source.concat(response.data.articles);
}
});
}
})
Now you have a $scope.source with all articles merged into one array.

AngularJs with REST Api

i'm new to angularJs and want to learn more about it, i'm trying to display some users from a fake REST Api, when trying to run my code i got empty page and the console doesn't give me any errors , i don't know where is the error or where i can debug.
app.js
var myApp = angular.module("app", []);
contactsData.service.js look like that :
(function () {
var app = angular.module("app");
app.service("contactDataSvc", function ($http) {
var self = this;
self.getContacts = function () {
var promise1 = $http.get("http://localhost:3000/contacts");
var promise2 = promise1.then(function (response) {
return response.data;
});
return promise2;
}
});
})();
contacts.controller.js
(function () {
var myApp = angular.module("app");
myApp.controller("contactsCtrl", contactsCtrl);
function contactsCtrl(contactDataSvc) {
contactDataSvc.getContacts()
.then(function(data){
this.contacts = data;
});
}
})();
finally my view index.html
<html ng-app="app">
<head>
<title></title>
<script src="angular.js"></script>
<script src="app.js"></script>
<script src="contacts.controller.js"></script>
<script src="contactsData.service.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" />
<!--<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>-->
</head>
<body class="container">
<div>
<div ng-controller="contactsCtrl as ctrl">
<div class="raw">
<ul class="list-group">
<li class="li-group-item" ng-repeat="obj in ctrl.contacts">
{{obj.name.title + " " + obj.name.first + " " + obj.name.last}}
</li>
</ul>
</div>
</div>
</div>
</body>
</html>
Small correction required in your contactsCtrl
function contactsCtrl(contactDataSvc) {
var vm = this;
contactDataSvc.getContacts()
.then(function(data){
vm.contacts = data;
});
}
You cannot use this inside the then callback as the scope will be different.
Corrected working example here : http://plnkr.co/edit/LLKJipkBbiZ17QjQpw1X
Refer more:
https://www.w3schools.com/js/js_scope.asp
What is the scope of variables in JavaScript?
1 - Is this url correct? http://localhost:3000/contacts
2 - Open the url on any browser, does it return any response ? JSON?
Please check this first to see if the problem is not on the server side.
Firstly inject $scope in controller because anything/data that we want to access over Html from controller needs to be binded on $scope.
So you controller would look like:
(function () {
var myApp = angular.module("app");
myApp.controller("contactsCtrl", contactsCtrl);
function contactsCtrl($scope,contactDataSvc) {
contactDataSvc.getContacts()
.then(function(data){
$scope.contacts = data;
});
}
})();
Secondly from the service you need to return a promise from it only then you will be able to get the data once the response is back from the API.
So,the updated service code is :
(function () {
var app = angular.module("app");
app.service("contactDataSvc", function ($http,$q) {
var self = this;
var defered = $q.defer();
self.getContacts = function () {
var promise1 = $http.get("http://localhost:3000/contacts");
promise1.then(function (response) {
defered.resolve(response.data);
});
return defered.promise;
}
});
})();

Use scope from multiple controllers on page

So i've split out my UI into subcomponents but then i realise that one of the components requires to be react to a dropdown change which is caught by the parent controller.
I can create a shared service for the variables and i have been able to inject the sub controller so that i can kick off functions BUT.
how do i then use the scope within the sub controller?
var ctrl1= $scope.$new();
$controller('ctrl', { $scope: ctrl1});
ctrl1.GetData();
this works fine. I can see data coming back in the console. BUT my ui doesnt change. What am i missing?
I've edited the post to illustrate what i'm attempting to do more clearly.
The drop down on change is caught by the parent controller but i then require the child controller to run away and get some data and update the UI.
It's an attempt to split out the components. Is this possible? Or have a split the components out too far?
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<script>
angular.module('app2', [])
.controller('ctrl2', ['$scope', '$http', function($scope, $http){
$scope.getdata = function(){
$http.post(WebServiceURL)
.success(function(data){
$scope.app2Data = "test2 data";
});
}
}]);
angular.module('app1', ['app2'])
.controller('ctrl1', ['$scope','$controller',function($scope, $controller){
$scope.name = 'Controller 1';
//just something to put in the ddp
$scope.data = [
{id:1, name: "test"},
{id:2, name: "test2"}
]
$scope.makeChanged = function(id){
//ddp has changed so i refresh the ui with some other data which is in got by ctrl2.
var cl2 = $scope.$new();
$controller('ctrl2', { $scope: cl2 });
cl2.getdata();
}
}]);
</script>
</head>
<body ng-app="app1">
<div ng-controller="ctrl1">
<p>here is: {{name}}</p>
<select ng-model="d" ng-options="d as dat.name for dat in data track by dat.id" ng-change="makeChanged(d.id)"></select>
<div>
{{app2Data.text}}
</div>
</div>
</body>
</html>
for anyone interested here's how i got round this.
I created a shared service between the two controllers. and created a callback on the service. i registered the call back on ctrl2 so when the shared variable changed the controller2 will do what i want it to and scope is freshed.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<script>
angular.module('app1', ['app2'])
.controller('ctrl1', ['$scope', '$controller', 'appointmentSharedProperties',
function($scope, appointmentSharedProperties) {
$scope.name1 = 'Controller 1';
console.log('ctrl1');
//just something to put in the ddp
$scope.data = [{
id: 1,
name: 'test'
}, {
id: 2,
name: 'test2'
}];
$scope.makeChanged = function(value) {
//ddp has changed so i refresh the ui with some other data which is in got by ctrl2.
appointmentSharedProperties.setDetail(value);
console.log('in makeChanged: ' + value);
}
}
]).service('appointmentSharedProperties', function() {
var test = '';
var __callback = [];
return {
getDetail: function() {
return test;
},
setDetail: function(value) {
test = value;
if (__callback.length > 0) {
angular.forEach(__callback, function(callback) {
callback();
});
}
},
setCallback: function(callback) {
__callback.push(callback);
}
};
});
angular.module('app2', [])
.controller('ctrl2', ['$scope', 'appointmentSharedProperties',
function($scope, appointmentSharedProperties) {
$scope.name2 = 'Controller 2';
console.log('ctrl2');
var getdata = function() {
console.log('in getdata');
$scope.app2Data = appointmentSharedProperties.getDetail();
}
appointmentSharedProperties.setCallback(getdata);
}
]);
</script>
</head>
<body ng-app="app1">
<div ng-controller="ctrl1">
<p>here is: {{name1}}</p>
<p>here is: {{name2}}</p>
<select ng-model="d" ng-options="d as dat.name for dat in data track by dat.id" ng-change="makeChanged(d.name)"></select>
<div>
{{app2Data}}
</div>
</div>
</body>
</html>
General example of how to pass variables from one controller to other
<html>
<head>
<meta charset="ISO-8859-1">
<title>Basic Controller</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js">
</script>
</head>
<body ng-app="myApp">
<div ng-controller="ctrl1">
{{greeting}}
</div>
<div ng-controller="ctrl2">
{{dataToHtml2}}
</div>
</body>
</html>
This is the javascript file for this
var myApp = angular.module('myApp',[]);
myApp.service('sampleService', function(){
var temp = '';
this.setValue = function(data){
temp = data;
}
this.getValue = function(){
return temp;
}
});
myApp.controller('ctrl1', function($scope,sampleService) {
$scope.greeting = 'This line is in first controller but I exist in both';
var data= $scope.greeting;
sampleService.setValue(data);
});
myApp.controller('ctrl2', function($scope, sampleService){
$scope.dataToHtml2 =sampleService.getValue();
});
Here is the blog that explains this flow : Frequently asked questions in angularjs
It has the demo of what I written. Happy coding..!!

Resources