I´m currently starting to learn Angular.JS and worked with a few tutorials like this this one. I followed the Steps but tryed to improve the code by saving single parts like controllers or services in seperate .js files because I heared this is a good habit. That was no problem and all worked fine. But when I came up with the Service which provides my posts I also tried to write some sort of API in the Service because i learned in another tutorial to do so.
There comes the Problem: The API to get my list of posts is working fine but if I try to send data due to an addPost function to the API it doesn´t work at all.
So can you maybe help me to find out what the problem is because I want to implement a Backend to the post-Service later on and want all $http requests at one place.
EDIT
The code-sample below is running now and you can see the problem if you try to add a post. The code stops after/during the addPost() function in the MainCtrl because the "clearing" of the HTML-form isn´t happening.
here you can find my code:
var app = angular.module('flapperNews', []);
app.controller('MainCtrl', function($scope, postService){
$scope.test = "Hello, World!";
$scope.posts = postService.getPosts();
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
postService.addPost({title: $scope.title, link: $scope.link, upvotes: 0});
//This code above was my try ith the API in posts.js
// $scope.posts.push({
// title: $scope.title,
// link: $scope.link, // this whole part is from the tutorial and works fine
// upvotes: 0
//});
$scope.title = '';
$scope.link = '';
};
$scope.incrementUpvotes = function(post) {
post.upvotes += 1;
};
});
app.factory('postService', function() {
var srv = {};
srv._posts = [
{title: 'post 1', link: '', upvotes: 5},
{title: 'post 2', link: '', upvotes: 2},
{title: 'post 3', link: '', upvotes: 15},
{title: 'post 4', link: '', upvotes: 9},
{title: 'post 5', link: '', upvotes: 4}
];
srv.getPosts = function() {
return angular.copy(srv._posts);
};
srv.addPost = function(post) { //function to put the new Post in the Array
srv._posts.push(post);
};
return {
getPosts: function() {
return srv.getPosts();
},
addPost: function(post) { //the public API to put the post in the Array
srv.addPost(post);
}
};
});
<!DOCTYPE html>
<html>
<head>
<meta charset="Utf-8">
<title>FlapperNews</title>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<style> .glyphicon-thumbs-up { cursor:pointer } </style>
</head>
<body ng-app="flapperNews" ng-controller="MainCtrl">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="page-header">
<h1>Flapper News</h1>
</div>
<div ng-repeat="post in posts | orderBy:'-upvotes'">
<span class="glyphicon glyphicon-thumbs-up"
ng-click="incrementUpvotes(post)"></span>
{{post.upvotes}}
<span style="font-size:20px; margin-left:10px;">
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
</span>
</div>
<form ng-submit="addPost()"
style="margin-top:30px;">
<h3>Add a new post</h3>
<div class="form-group">
<input type="text"
class="form-control"
placeholder="Title"
ng-model="title"></input>
</div>
<div class="form-group">
<input type="text"
class="form-control"
placeholder="Link"
ng-model="link"></input>
</div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
</div>
</div>
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src=scripts/app.js></script>
<script src=scripts/controller/main.js></script>
<script src=scripts/service/posts.js></script>
</body>
</html>
Once you push the data to the service you should update $scope.posts
$scope.addPost = function(){
if(!$scope.title || $scope.title === '') { return; }
postService.addPost({title: $scope.title, link: scope.link, upvotes: 0});
$scope.posts = postService.getPosts();
// or edit postService.addPost so you can make
/* $scope.posts = postService.addPost({title: $scope.title, link: scope.link, upvotes: 0}); */
$scope.title = '';
$scope.link = '';
};
Related
I have been going through the this MEAN Stack tutorial at following along however I have changed my code to use Controller as rather than having $scope like they do in their code.
I am stuck on the enabling upvotes portion. When I click it does not increase the number of upvotes and I am not sure why this happening.
Can anyone help resolve this? Here is my code:
index.html
<html>
<head>
<title>My Angular App!</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="flapperNews" ng-controller="MainCtrl as main">
<div ng-repeat="post in main.posts | orderBy: '-upvotes'">
<span ng-click="incrementUpvotes(post)">^</span>
{{ post.title }} - upvotes: {{ post.upvotes }}
</div>
<form ng-submit="main.addPost()">
<input type="text" ng-model="main.title"></input>
<button type="submit">Add Post</button>
</form>
</body>
</html>
app.js
/*global angular*/
/*jslint white:true*/
angular
.module('flapperNews', [])
.controller('MainCtrl', function(){
'use strict';
var main = this;
main.posts = [
{title: 'post 1', upvotes: 5},
{title: 'post 2', upvotes: 2},
{title: 'post 3', upvotes: 15},
{title: 'post 4', upvotes: 9},
{title: 'post 5', upvotes: 4}
];
main.addPost = function(){
if(!main.title || main.title === '') {return;}
main.posts.push({title: main.title, upvotes: 0});
main.title = '';
};
main.incrementUpvotes = function(post) {
post.upvotes += 1;
};
});
The problem you're having is with ng-repeat. You need to change your code to $parent.incrementUpvotes(post) to make this work.
Here's why: ng-repeat creates a new child scope for each iteration, but you don't have full access to everything you might need. This is due to how angular copies properties into the child scope. In order to access the scope that actually contains a definition for incrementUpvotes (the controller scope), you need to move up into the parent scope first. Alternatively you could probably do main.incrementUpvotes(post) to accomplish the same thing since you're aliasing the controller.
You can see a more detailed explanation of what happens when angular creates a child scope, and why certain properties are not inherited here https://github.com/angular/angular.js/wiki/Understanding-Scopes
What happens is that the child scope gets its own property that
hides/shadows the parent property of the same name. This is not
something AngularJS is doing – this is how JavaScript prototypal
inheritance works. New AngularJS developers often do not realize that
ng-repeat, ng-switch, ng-view and ng-include all create new child
scopes, so the problem often shows up when these directives are
involved.
Just add main.incrementUpvotes(post) instead of incrementUpvotes(post).
angular
.module('flapperNews', [])
.controller('MainCtrl', function(){
'use strict';
var main = this;
main.posts = [
{title: 'post 1', upvotes: 5},
{title: 'post 2', upvotes: 2},
{title: 'post 3', upvotes: 15},
{title: 'post 4', upvotes: 9},
{title: 'post 5', upvotes: 4}
];
main.addPost = function(){
if(!main.title || main.title === '') {return;}
main.posts.push({title: main.title, upvotes: 0});
main.title = '';
};
main.incrementUpvotes = function(post) {
post.upvotes += 1;
};
});
<html>
<head>
<title>My Angular App!</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="flapperNews" ng-controller="MainCtrl as main">
<div ng-repeat="post in main.posts | orderBy: '-upvotes'">
<span ng-click="main.incrementUpvotes(post)">^</span>
{{ post.title }} - upvotes: {{ post.upvotes }}
</div>
<form ng-submit="main.addPost()">
<input type="text" ng-model="main.title"></input>
<button type="submit">Add Post</button>
</form>
</body>
</html>
I am trying to to get a JSON array from a server side PHP file. I have the PHP set up to query a MySQL database and return the result as a JSON array. I'm using the ionic framework to develop an app. At the moment I have the app working with a hard coded JSON array, this is what needs to be replaced by the array gained from the PHP.
This is the file where the chats variable should contain the JSON array from the PHP file.
angular.module('starter.services', [])
.factory('Chats', function() {
// Might use a resource here that returns a JSON array
// Some fake testing data
var chats = [{
id: 0,
name: 'Ben Sparrow',
lastText: 'You on your way?',
face: 'img/ben.png'
}, {
id: 1,
name: 'Max Lynx',
lastText: 'Hey, it\'s me',
face: 'img/max.png'
}, {
id: 2,
name: 'Adam Bradleyson',
lastText: 'I should buy a boat',
face: 'img/adam.jpg'
}, {
id: 3,
name: 'Perry Governor',
lastText: 'Look at my mukluks!',
face: 'img/perry.png'
}, {
id: 4,
name: 'Mike Harrington',
lastText: 'This is wicked good ice cream.',
face: '/img/mike.png'
}];
return {
all: function() {
return chats;
},
remove: function(chat) {
chats.splice(chats.indexOf(chat), 1);
},
get: function(chatId) {
for (var i = 0; i < chats.length; i++) {
if (chats[i].id === parseInt(chatId)) {
return chats[i];
}
}
return null;
}
};
});
Here is where the array is accessed from within the application:
<ion-view view-title="Chats">
<ion-content>
<ion-list>
<ion-item class="item-remove-animate item-avatar item-icon-right" ng-repeat="chat in chats" type="item-text-wrap" href="#/tab/chats/{{chat.id}}">
<div class="list card">
<div class="item item-avatar">
<img src="{{chat.face}}">
<h2>{{chat.name}}</h2>
<p>{{chat.lastText}}</p>
</div>
<div class="">
<img ng-src="{{chat.face}}">
</div>
<a class="item item-icon-left assertive" href="#/tab/chats/{{chat.id}}">
<i class="icon ion-cash"></i>
Get Deal!
</a>
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
and below is the PHP file used:
<?php
define('HOST','host');
define('USER','user');
define('PASS','password');
define('DB','db');
$con = mysqli_connect(HOST,USER,PASS,DB);
$sth = mysqli_query($con, "SELECT * FROM chats;");
$rows = array();
while($r = mysqli_fetch_assoc($sth)) {
$rows[] = $r;
}
echo json_encode($rows);
mysqli_close($con);
?>
This is the controller.js:
angular.module('starter.controllers', [])
.controller('DashCtrl', function($scope) {})
.controller('ChatsCtrl', function($scope, Chats) {
// With the new view caching in Ionic, Controllers are only called
// when they are recreated or on app start, instead of every page change.
// To listen for when this page is active (for example, to refresh data),
// listen for the $ionicView.enter event:
//
//$scope.$on('$ionicView.enter', function(e) {
//});
$scope.chats = Chats.all();
$scope.remove = function(chat) {
Chats.remove(chat);
};
})
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
$scope.chat = Chats.get($stateParams.chatId);
})
.controller('AccountCtrl', function($scope) {
$scope.settings = {
enableFriends: true
};
});
I've tried using an async call (which i'm not totally familiar with). I need the array to be ready at the start of the app
Thanks!
This works :
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('chats', function($http){
var chats = [];
var _loading = $http.get('http://swapi.co/api/people').then(function(res){
console.log(res.data.results);
chats = res.data.results;
});
return {
loading: _loading,
all: function(){
return chats;
}
};
});
myApp.controller('ChatsCtrl', function($scope, chats){
$scope.chats = [];
chats.loading.then(function(){
$scope.chats = chats.all();
});
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="ChatsCtrl">
<ul>
<li ng-repeat="chat in chats">{{chat.name}}</li>
</ul>
</div>
</body>
</html>
Since the Ionic framework is built on Angular, you can use the $http service. You need to request that PHP file from the $http service and then you will be able to read it as JSON. Try something like this for starters:
Make a service that has your API set up already, then call it in your controller file.
angular.module('starter.services', [])
.factory('MYAPI', function() {
return {
getChats: function() {
return $http.get('http://localhost/YOURFILEHERE.php');
}
}
});
Now, in your controller file, assuming you've injected the MYAPI service, you can call
MYAPI.getChats().then(function(response) {
$scope.chats = response.data;
}, function(error) {
console.error(error);
});
You will need to change the $http.get() path to reflect the path of the PHP file on your system.
I am learning AngularJS from codeSchool and I was making a simple hello world app , initially it was being rendered properly but after some time It didn't work at all. I am not able to detect the bug , please help
Here is the code for html file
<!DOCTYPE html>
<html ng-app="store">
<head>
<title>Angular Code School</title>
<link rel="stylesheet" href="bootstrap.min.css">
</head>
<body>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="app.js"></script>
I am {{4+6}}
{{"Hello +"World"}}
<div ng-controller="StoreCtrl as store">
<div ng-repeat="product in store.products| orderBy:'-price'">
<h2>Name :{{product.name}} </h2>
<h2>Price:{{product.price | currency}} </h2>
<h2>Description:{{product.description}} </h2>
<button ng-show="product.canPurchase">Add To Cart </button>
<section ng-controller="PanelCtrl as panel">
<ul class="nav nav-pills">
<li ng-class="{'active':panel.isSelectedTab(1)}"><a href ng-click="panel.selectTab(1)"> Description</a></li>
<li ng-class="{'active':panel.isSelectedTab(2)}"><a href ng-click="panel.selectTab(2)">Specs</a></li>
<li ng-class="{'active':panel.isSelectedTab(3)}"><a href ng-click="panel.selectTab(3)">Reviews</a></li>
</ul>
<div ng-show="panel.isSelectedTab(1)">This is description div</div>
<div ng-show="panel.isSelectedTab(2)">This is Specification Section</div>
<div ng-show="panel.isSelectedTab(3)">This is Reviews section</div>
</section>
</div>
</div>
</body>
</html>
appTest.js
var app = angular.module('store', []);
app.controller('StoreCtrl', ['$scope', function ($scope) {
this.products = gems;
}])
gems = [{
name: 'Dodecahedron',
price: 2.95,
description: 'This is the description of Dodecahedron'
canPurchase: false;
},
{
name:'Diamond',
price: 5.95,
description: 'Diamond is the most luxuriest gem of all.'
canPurchase:true;
}]
app.controller('PanelCtrl', ['$scope', function ($scope) {
this.tab=1;
this.selectTab = function(setTab) {
this.tab = setTab;
};
this.isSelectedTab = function(checkTab){
return this.tab===checkTab;
}
}])
The structure of my directory is like
root/
angular.js
appTest.js
index.html
Here is the page with console
appTest.js
var app = angular.module('store', []);
app.controller('StoreCtrl', function() {
this.products = gems;
});
app.controller('PanelCtrl', function() {
this.tab = 1;
this.selectTab = function(setTab) {
this.tab = setTab;
};
this.isSelected = function(checkTab) {
return this.tab === checkTab;
};
});
var gems =
[{
name: 'Dodecahedron',
price: 2.95,
description: 'This is the description of Dodecahedron',
canPurchase: false
},
{
name: 'Diamond',
price: 5.95,
description: 'Diamond is the most luxuriest gem of all.',
canPurchase: false
}];
and in index.html
{{"Hello" +"World"}} should be {{"Hello" + "World"}}
You're messing a double quote:
{{"Hello +"World"}}
should be:
{{"Hello " + "World"}}
Check your console for javascript error.
Three issues:
Modify the hello words as below
{{ "Hello" + "World"}}
in your appTest.js,
add the comma after description fields of the 'gem'
remove the ";" semicolon after "canPurchase"
in your html file
ensure you are including "appTest.js" and not just "app.js"
I am currently working on a small angularjs app which is basically a user profile management app.
The problem i am having is with adding users dynamically. When i enter the user data, it successfully POST's to my local server i have setup, BUT i have to refresh the page to see the new user in the users list
I obviously dont want to have to refresh.
-Yes i've tried $scope.apply() after running the POST function
Something i am noticing with Angular Batarang (Debugging tool), is that the scope is updating fine, but there is a blank spot or 'null' value where the new user should be.
Here are the Controllers:
UsersApp.controller('UserListController', [ '$scope', 'userService', function($scope, userService) {
$scope.usersList = userService.usersList;
$scope.users = userService.users;
$scope.user = userService.user;
}]);
UsersApp.controller('AddUserController', function($scope, $window, dataResources, userService) {
$scope.addNew = function addNew(newUser) {
$scope.usersList = userService.usersList;
var firstName = newUser.firstName;
var lastName = newUser.lastName;
var phone = newUser.phone;
var email = newUser.email;
$scope.newUserData = {
firstName , lastName, phone , email
}
new dataResources.create($scope.newUserData);
$scope.usersList.push(dataResources);
$scope.$apply();
};
And Here are my views:
Add User:
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="js/minimize.js"></script>
<div ng-controller="AddUserController">
<div class="userInfo" id="usernameDiv">
<h2 id="username">User<img id="showhide" src="images/plus.png" style="position:absolute; padding-left:15px; width:31px; color:white;"></h2>
</div>
<div class="userInfo">
<div id="listInfo">
<form ng-controller="AddUserController">
<input type="text" placeholder= "First Name" ng-model="newUser.firstName"></input>
<input type="text" placeholder= "Last Name" ng-model="newUser.lastName"></input>
<input type="text" placeholder= "Phone Number" ng-model="newUser.phone"></input>
<input type="text" placeholder= "Email" ng-model="newUser.email"></input>
<button type="submit" ng-click="addNew(newUser)">Add User</button>
</form>
</div>
</div>
Users List:
<!DOCTYPE html>
<html>
<head></head>
<body id="">
<div ng-controller="UserListController">
<div class="userInfo">
<h2>List of Users</h2>
<div id="listInfo">
<ul style="list-style-type: none;">
<li ng-repeat="user in usersList">
<!--<p class="userData">ID: {{ user }}</p> -->
<p class="userData"><a style="cursor:pointer;" ui-sref="UserProfile">{{ user.firstName }}</a></p>
</li>
</ul>
</div>
</div>
Factory and Service:
UsersApp.factory('dataResources', [ '$resource', function($resource) {
return $resource('http://localhost:24149/users/:id', {}, {
query: {method:'GET', params:{idnum: '#id'}, isArray:true},
create: {method:'POST', headers: { 'Content-Type': 'application/json' }},
update: {method:'PUT', params:{idnum: '#id'}},
remove: {method:'DELETE', params:{idnum:'#id'}, isArray:true}
});
}]);
UsersApp.service('userService', function(dataResources) {
return {
usersList: dataResources.query()
}
});
I'm not sure if I follow exactly, but I believe you need to deal with a promise from your POST and then push the result. e.g.,
dataResources.create($scope.newUserData).$promise.then(function(data) {
$scope.usersList.push(data);
});
Your service will return a promise and then when the POST is complete your service should return the new user and you just add it to your current list.
See $resource documentation:
non-GET "class" actions: Resource.action([parameters], postData, [success], [error])
According to the doc your code should look like this:
dataResources.create($scope.newUserData,
function(data) {
$scope.usersList.push(data);
}
);
controller: you don't need to make a new userdata object, you can just use newUser
UsersApp.controller('AddUserController', function($scope, $window, dataResources, userService) {
$scope.usersList = userService.usersList;
$scope.addNew = function addNew(newUser) {
dataResources.create($scope.newUser,
function(data) {
$scope.usersList.push(data);
}
);
};
};
Same idea for angular2 using observables.
public posts: any;
onPost(input) {
this.dataService.jsonserverPost(input)
.subscribe(
(data: any) => {
this.posts.push(data);
}
);
}
I am following the tutorial on thinkster.io.
Here is my controller:
app.controller('PostsCtrl', function ($scope, Post){
$scope.posts = Post.get();
$scope.post = {url: 'http://', title: ''};
Post.save($scope.post, function (ref) {
$scope.posts[ref.name] = $scope.post;
//$scope.post = {url: 'http://', title: ''};
});
$scope.submitPost = function () {
Post.save($scope.post);
//$scope.post = {url: 'http://', title: ''};
};
$scope.deletePost = function (postId) {
Post.delete({id: postId}, function () {
delete $scope.posts[postId];
});
};
});
Here is the HTML:
<div ng-repeat="(postId, post) in posts">
{{post.title}}
<a ng-click="deletePost(postId)">delete</a>
</div>
<!--<form ng-submit="submitPost()">-->
<!--<input type="text" ng-model="post.title" />-->
<!--<input type="text" ng-model="post.url" />-->
<!--<input type="submit" value="Add Post" />-->
<!--</form>-->
Posts: {{ posts }}<br />
Post: {{ post }}
Whenever I reload the page and extra object {url: 'http://', title: ''} would get added to $scope.posts. The commenting I did does not make the difference. How can I prevent the POST request from happening?
In case you want the full code. Here it one that someone posted on github