I am trying to request some data from node.js server from my angular.js. The problem is that upon data response i see a blank browser window with my json object printed on it. I want angular.js to recognize the response and stay on page.
HTML form - template that gets loaded with loginController
<section class="small-container">
<div class="login-form">
<form action="/login" method="post" ng-submit="processForm()">
<input ng-model="formData.username" type="text" name="username">
<input ng-model="formData.password" type="password" name="password">
<button>login</button>
</form>
</div>
</section>
Angular.JS
var app = angular.module("blavor", ['ngRoute']);
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when("/", {
templateUrl: "/index",
controller: "loginController"
})
.when("/register", {
templateUrl: "/register",
controller: "registerController"
})
.otherwise("/");
$locationProvider.html5Mode(true);
}]);
app.controller('loginController', function($scope, $http) {
$scope.formData = {};
$scope.processForm = function() {
$http({
method: 'POST',
url: '/login',
data: $.param($scope.formData),
processData: false,
responseType: "json",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function(data) {
console.log(data);
if (!data.success) {
alert("Noo!");
} else {
alert("YEEEY!");
}
});
};
});
Node.js Server - index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var express = require('express');
var bodyParser = require('body-parser');
app.use( bodyParser.json() );
app.use( bodyParser.urlencoded({ extended: false }) );
var routes = require('./routes')(app);
http.listen(3000, function() {
console.log('listening on *:3000');
});
module.exports.start = start;
Node.js Server - routes
module.exports = function(app) {
app.post('/login', function(request, response) {
console.log(request.body);
response.setHeader('Content-Type', 'application/json');
response.end(JSON.stringify({value:"somevalue"}));
});
}
I am using AngularJS v1.2.24 and Node.js v0.10.25
console.log(data) in angular never gets called..
Hi try removing the action and method from your form.
From the ng-submit docs
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page), but only if the form does not contain action, data-action, or x-action attributes.
So by adding those, you are causing the page to refresh when the form is submitted.
Without them, angular will call $event.preventDefault() for you, which stops the page from being reloaded.
EDIT: Just to add, you were seeing the correct data from the server because you're responding with preset data, which will always be provided when someone posts to /login.
So your form is currently circumventing angular entirely, and directly getting the data from the server.
Related
I am doing an online tutorial where they teach you to make a simple web-app using MEAN.The code below is for editing the given collection of JSON objects(Videos are JSON objects here)
The collection is at
/api/videos
So I have to click on a href="/#/video/{{video._id}} which takes me to form.html and I have the option of editing the 'title' and 'description' parameters of the JSON object.
What I can't seem to understand is:
a)Why is this (full code below in the question) required
var Videos = $resource('/api/videos/:id', { id: '#_id' },
{
update: { method: 'PUT' }
});
Since I am on href="/#/video/{{video._id}} can't I directly take the id from the URL
var Videos=$resource('api/videos)
Videos.get({ id: $routeParams.id }, function(video){
$scope.video = video;
});
b)Whait is the workflow(i.e when is the router.get() request exactly made and when is the router.put() request made)
According to me when I click on the save button the Controller makes a put request to the API but I can't figure out when the router.get() request is being made
I am trying to read up express and angular documentations but they don't seem to explain the workflow.
Could you also please tell me what should I read up to get a better understanding?
This is the form.html code
<h1>Add a Video</h1>
<form>
<div class="form-group">
<label>Title</label>
<input class="form-control" ng-model="video.title"></input>
</div>
<div>
<label>Description</label>
<textarea class="form-control" ng-model="video.description"></textarea>
</div>
<input type="button" class="btn btn-primary" value="Save" ng-click="save()"></input>
</form>
This is the controller code
app.controller('EditVideoCtrl', ['$scope', '$resource', '$location', '$routeParams',
function($scope, $resource, $location, $routeParams){
var Videos = $resource('/api/videos/:id', { id: '#_id' },
{
update: { method: 'PUT' }
});
Videos.get({ id: $routeParams.id }, function(video){
$scope.video = video;
});
$scope.save = function(){
Videos.update($scope.video, function(){
$location.path('/');
});
}
}]);
This is the API Endpoint Code
router.get('/:id', function(req,res){
var collection =db.get('videos');
collection.findOne({_id: req.params.id},function(err,video){
if(err) throw err;
res.json(video);
});
});
router.put('/:id', function(req, res){
var collection=db.get('videos');
collection.update({_id:req.params.id},
{title: req.body.title,
description: req.body.description
},
function (err,video)
{if (err) throw err;
res.json(video);
});
});
Well, according to AngularJS docs for $resouce, $resource is:
A factory which creates a resource object that lets you interact with
RESTful server-side data sources.
In other words is a shortcut for RESTful services operations. The code bellow creates an interface with an API endpoint to make REST operations more easy to do.
Once you have this:
var User = $resource('/user/:userId', {userId:'#id'});
Is much easier to do this:
User.get({userId:123}, function(user) {
user.abc = true;
user.$save();
});
Because RESTful is a standard, and $resource is the Angular's implementation of the consumption of API's in this standard. On his internals, is made an assynchronous request with the propper headers and method according to the operation you conigured and choosed.
I want create server for uploading images and filling json via form. I have tried many codes and plugins for downloading to server, but I have always get 403 error. What is my mistake. I have used only jQuery or AngularJs without backend. This is a link: http://salegid.com/dist/ The last one variant:
HTML
<div ng-app="myApp">
<div ng-controller="MyController">
<input type="file" fileread="uploadme" />
<img src="{{uploadme}}" width="100" height="50" alt="Image preview...">
<br/>
<p>
Image dataURI:
<pre>{{uploadme}}</pre>
</p>
<br/>
<button ng-click="uploadImage()">upload image</button>
</div>
</div>
JS
var app = angular.module('myApp', [
'ngResource',
'ngRoute'
])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'index.html',
controller: 'MyController',
})
.otherwise({
redirectTo: '/'
});
}])
.controller('MyController', ['$scope', '$http', function($scope, $http) {
//the image
$scope.uploadme;
$scope.uploadImage = function() {
var fd = new FormData();
var imgBlob = dataURItoBlob($scope.uploadme);
fd.append('file', imgBlob);
$http.post(
'imageURL',
fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}
)
.success(function(response) {
console.log('success', response);
})
.error(function(response) {
console.log('error', response);
});
};
//you need this function to convert the dataURI
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {
type: mimeString
});
};
}])
.directive('fileread', [
function() {
return {
scope: {
fileread: '='
},
link: function(scope, element, attributes) {
element.bind('change', function(changeEvent) {
var reader = new FileReader();
reader.onload = function(loadEvent) {
scope.$apply(function() {
scope.fileread = loadEvent.target.result;
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}
]);
Can you help me because I'm stuck. Thanks a lot.
403 means Forbidden request. This means that the server hasn't gotten all of the authentication credentials it needs from your request. Please check with your backend and see what headers are required.
403 FORBIDDEN
The server understood the request but refuses to authorize it.
A server that wishes to make public why the request has been forbidden can describe that reason in the response payload (if any).
If authentication credentials were provided in the request, the server considers them insufficient to grant access. The client SHOULD NOT automatically repeat the request with the same credentials. The client MAY repeat the request with new or different credentials. However, a request might be forbidden for reasons unrelated to the credentials.
An origin server that wishes to "hide" the current existence of a forbidden target resource MAY instead respond with a status code of 404 Not Found.
I see from your code that you're not setting any authentication headers. In AngularJS, app level auth headers can be set using:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common['Authorization'] = /* ... */;
}])
I'm creating a MEAN stack blog app and what I'm trying to accomplish is getting a "blog" from a list of blogs(div with ng-repeat) which I have saved to my Mongo database using a Mongoose schema to render in a seperate HTML view.
Specifically, I want to be able to click on the <button class="readPost" ng-click="readPost(post._id)">Read Blog</button> in main.html and have that data to be rendered through AngularJS' data-binding in readblog.html.
What I have tried:
1.) I have tried putting a $location.path('/readblog' + id); in the readPost function, but I'm assuming that doesn't work if that path is not specifically declared in my app.js file.
2.) Putting a res.redirect('/readblog'); and a res.redirect('/readblog' + id); in the API call in server.js.
...and now I'm currently looking to see if there are any examples of this problem or alternative methods for achieving this functionality I'm trying to get.
I'm fairly new to coding in general, so I will be happy to clarify on anything that doesn't necessarily make sense here.
Here's what my code looks like:
server.js
//Dependencies.
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var http = require('http');
var path = require('path');
var fs = require('fs');
var port = 9001;
var mongoUri = 'mongodb://localhost:27017/blog-app';
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());
var Schema = mongoose.Schema;
var blogSchema = new Schema({
title : {type: String, min: 8, max: 50, required: true},
body : {type: String, required: true},
author : {type: String, min: 3, max: 40, required: true},
pubdate : {type: Date, default: Date.now}
});
var Blog = mongoose.model('Blog', blogSchema);
app.get('/api/blogs/:blog_id', function(req, res) { //Get Blog by ID.
Blog.find({
_id: req.params.blog_id
}, function(err, blog) {
if (err)
res.send(err);
});
});
mongoose.connect(mongoUri);
mongoose.connection.once('open', function() {
console.log("We are now connected to MongoDB at: ", mongoUri);
});
app.listen(port, function() {
console.log('Listening on port: ', port);
});
mainCtrl.js
var app = angular.module("blog-app");
app.controller('MainController', ['$scope', '$http', '$location', function($scope, $http, $location) {
$scope.apptitle = "AngularJS Blog";
$scope.formData = {};
$http.get('/api/blogs').success(function(data){
$scope.blog = data;
console.log(data);
}).error(function(data) {
console.log('Error: ' + data);
});
$scope.readPost = function(id) {
$http.get('/api/blogs/' + id)
.success(function(data) {
$scope.readblog = data;
console.log('This is the blog you selected: ', data);
});
};
}]);
app.js
var app = angular.module('blog-app', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainController'
})
.when('/newblog', {
templateUrl: 'views/newblog.html',
controller: 'MainController'
})
.when('/readblog', {
templateUrl: 'views/readblog.html',
controller: 'MainController'
})
.otherwise({
redirectTo: '/'
});
}) //End Config.
main.html
<div>
<div class="wrapper">
<div class="container" ng-repeat="post in blog">
<p><i class="fa fa-book"></i> {{ post.title }}</p>
<p>by {{ post.author}}</p>
<p>{{ post.pubdate | date }}</p>
<br>
<div>
<p>{{ post.body }}</p>
</div>
<br><br>
<div style="position: absolute; bottom: 10px; right: 10px;">
<button class="deletePost" ng-click="deletePost(post._id)">Delete Blog</button>
<button class="readPost" ng-click="readPost(post._id)">Read Blog</button>
</div>
</div>
</div>
</div>
readblog.html
<div style="padding-top: 150px">
<h2>Title: {{ readblog.title }}</h2>
<h2>Author: {{ readblog.author }}</h2>
<h2>Date: {{ readblog.pubdate }}</h2>
<h2>Body: {{ readblog.body }}</h2>
</div>
What you can do is drop your ngclick and use nghref to navigate to the blog post with selected id, then async load it and and assign it to your blog post scope.
If you have to do it programmatically, use $location and define path for the blog to accept id's.
.when('/readblog/:blogId',...
Similar question
First of all, we need to separate two things; client and server.
Your issue here is about the client side. I suggest you reading through https://github.com/angular-ui/ui-router documentation for your purpose; that is to pass data from one state to another. In your case it is the blogid of the selected blog. Then in your second state, you can retrieve your blogid by $Stateparams and by making a get request to your server to
/api/blogs/:blog_id
Something like
$stateProvider
.state('blog', {
url: "/blogs",
templateUrl: "views/blog.html"
})
.state('readblog', {
url: "/blogs/:blogid",
templateUrl: "views/readblog.html",
params: {
'id':'123456'
})
would do the work.
I am pretty new to Node.js, Express and angularjs. I am working on a simple Sign-in functionality that will redirect to another page if sign in success. I know I can use window.location for the redirect purpose, but I am trying to use res.render because I also want to pass some values to the new page.
However, the res.render doesn't seem to work, the result page never shows up.
Signin.ejs:
<div id="navbar" class="navbar-collapse collapse" ng-controller="signinController">
<form class="navbar-form navbar-right">
<div class="form-group">
<input type="email" ng-model="inputEmail" placeholder="Email" class="form-control">
</div>
<div class="form-group">
<input type="password" ng-model="inputPassword" placeholder="Password" class="form-control">
</div>
<button type="submit" ng-click="signIn()" class="btn btn-success">Sign in</button>
</form>
</div>
The javascript embedded is:
function signinController($scope,$http,$location) {
$scope.signIn = function() {
$http({
method: 'POST',
url: '/signin',
data: { "inputEmail": $scope.inputEmail, "inputPassword": $scope.inputPassword }
});
};
}
app.js
app.get('/result', home.result);
app.post('/signin', home.afterSignIn);
The home.js
function afterSignIn(req,res)
{
// check user already exists
var sqlStr="select * from users where email='"+req.param("inputEmail")+"' and password='"+req.param("inputPassword")+"'";
console.log("Query is:"+sqlStr);
res.render('result', { result: 'sqlStr' });
}
exports.result=function(req,res){
res.render('result');
}
exports.afterSignIn = afterSignIn;
result.ejs
<%= result %>
Any suggestions or working examples are highly appreciated :)
I think you are bit confused. Use express as the REST engine when it comes to routes. Angular routes will take care of the display logic and view routing on the client side.
I would suggest you to pass JSON data to front end angular and let it do the job for you. For example:
app.get('/', function (req, res) {
res.json({
title : "n562d",
strapline : "Please Log In"
})
});
You can access the API at the endpoint: http://localhost:3000/ Use $resource services to access the express endpoint.
example:
var MyResource = $resource('/');
var myResource = new MyResource();
myResource.$get(function(result){
//result holds -->{title : "n562d", strapline : "Please Log In"}
//use $location to change the uri, which is handled by Angular route config
$location.path('/')
});
For angular routing,i would suggest you to use ui-router.
example:
function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise("/");
$stateProvider
.state('index', {
url: "/",
templateUrl: 'app/authorization/index.tpl.html',
controller: 'AuthController'
})
.state('login', {
url: "/login/",
templateUrl: 'app/authorization/login.tpl.html',
controller: 'AuthController'
})
.state('signup',{
url: "/signup/",
templateUrl : 'app/authorization/signup.tpl.html',
controller: 'AuthController'
});
}
]);
Let me know if you need more detailed answer then i will update it. I hope it helps.
Feel free to look for similar implementation here.
I am building an app using Angular.js, Node.js, and Socket.io (among other things). My issue is that when I try to follow a link routing me to a login page, I end up in an infinite loop. The jquery document.ready function is called over and over, and each time this happens another socket connects to the user. The page won't even load because this keeps getting called. I am really stuck, so any help would be greatly appreciated.
Here is the configuration for the client side routing:
window.app = angular.module('MEAN', ['ngCookies', 'ngResource']);
window.app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', { templateUrl: 'views/index.html' }).
when('/signin', {
templateUrl: '/partials/signin',
controller: SigninCtrl
}).
when('/signup', {
templateUrl: '/partials/signup',
controller: SignupCtrl
}).
otherwise({redirectTo: '/'});
}]);
//Removing tomcat unspported headers
window.app.config(['$httpProvider', function($httpProvider, Configuration) {
//delete $httpProvider.defaults.headers.common["X-Requested-With"];
}]);
//Setting HTML5 Location Mode
window.app.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix("!");
}]);
Here is the controller:
function SigninCtrl($scope, $http, $location) {
$scope.form = {};
$scope.title = "Sign In";
$scope.SignIn = function() {
$http.post('/users/session', $scope.form).
success(function(data){
console.log("Successful sign in", data);
$location.path('/');
})
.error(function (data) {
console.log("There was an error");
$scope.errors = data.errors;
});
};
}
And here are the jade templates I am using for the partials:
extends ../layouts/default
block content
.row
.offset1.span5
a(href="/auth/facebook")
img(src="/img/icons/facebook.png")
a(href="/auth/github")
img(src="/img/icons/github.png")
a(href="/auth/twitter")
img(src="/img/icons/twitter.png")
a(href="/auth/google")
img(src="/img/icons/google.png")
.span6
if (typeof errors !== 'undefined')
.fade.in.alert.alert-block.alert-error
a.close(data-dismiss="alert", href="javascript:void(0)") x
ul
each error in errors
li= error.type
block auth
extends auth
block auth
form.signin.form-horizontal(class="simple-form")
.control-group
label.control-label(for='email') Email
.controls
input#email(type='text', name="email", placeholder='Email')
.control-group
label.control-label(for='password') Password
.controls
input#password(type='password', name="password", placeholder='Password')
.form-actions
button(ng-click='SignIn()') Sign in
| or
a.show-signup(href="/signup") Sign up
And here is the document ready function:
window.bootstrap = function () {
angular.bootstrap(document, ['MEAN']);
}
window.init = function () {
window.bootstrap();
}
window.connectSocket = function(){
var socket = io.connect();
socket.on('connect', function(message){
console.log("socket connected");
});
}
$(document).ready(function () {
//Fixing facebook bug with redirect
console.log("Document ready!");
if (window.location.hash == "#_=_") window.location.hash = "";
window.init();
window.connectSocket();
});
I feel dumb, but I figured out the issue. Similar to this issue: What web server configuration is required to make AngularJS routing function correctly?
I actually moved the routing from the server to the client earlier and in the partial template I had include auth and in the auth file I had an include for the header template, something that angular did already. In the end it was trying to include the same header in a loop... Hope this might help someone with the same issue later. Just make sure you don't have the header included multiple times...