Angular Submit Syntax and message if no results found using MovieDB API - javascript

I'm super new at web development and am trying to learn how to use Angular for a mini project. I'm using The MovieDB's restful API's and all I want to do is a simple search for a movie title, return results that are found, and return a message if nothing is found.
Unfortunately I'm hitting a few comprehension hurdles and I have looked for a solution but haven't found one that matches what I'm doing, which I think is pretty simple (most of the ones I've seen are for more complex approaches and I think it's just beyond my understanding for the moment)
All I want to do right now is have a searchbar, a user types in a movie name, clicks submit, and the angular app will return results. But I can't quite figure out how to pass the submit through to my app. Here is my html code:
<!doctype html>
<html>
<head>
<link
href="http://s3.amazonaws.com/codecademy-content/projects/bootstrap.min.css"
rel="stylesheet" />
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js">
</script>
<!-- Modules -->
<script src="js/app.js"></script>
<!-- Controllers -->
<script src="js/controllers/MainController.js"></script>
<link href="css/main.css" rel="stylesheet" />
</head>
<body ng-app="myApp">
<div class="header">
<img src="img\logo.png"
style="width: 80px; height: 80px;>
<div class="container">
<h1>The MovieDB Search Tool</h1>
<h2>Search for a movie!</h2>
</div>
<div class="main" ng-controller='MainController'>
<div class="searchbar">
<form ng-submit="submitFunction(field)">
<input type="text" name="field" placeholder="Search for a
movie">
<input type="submit" value="Submit">
</form>
</div>
<div class="container">
<div ng-repeat="details in movieList" class="col-md-6">
<div class="thumbnail">
<img ng-
src="https://image.tmdb.org/t/p/w154{{details.poster_path}}">
<p>{{ details.title }}</p>
<p class="date">Release Date: {{ details.release_date | date
}}</p>
<p>{{details.overview}}</p>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="container"></div>
</div>
</body>
</html>
And my javascript code for the angular app:
app.controller('MainController', ['$scope', '$http', function($scope, $http) {
$scope.movieTitle = function submitFunction(field){
}
$http.get('https://api.themoviedb.org/3/search/movie?api_key='+api_key+'&language=en-US&query='
+$scope.movieTitle+'&page=1&include_adult=false')
.then(successCallback, errorCallback);
function successCallback(response){
$scope.movieList = response.data.results
}
function errorCallback(error){
}
}]);
If I plug in a movie name like 'Deadpool' the html works just fine, of course with a static value it runs automatically. And I need it to work on submit, and the way I'm trying isn't working. I would think I need to get a variable passed in to the $scope, buy the submit function but I'm not getting anything when I run this.
If I could get to this point, I think I could figure out the logic to display a message of no results found, it should be as simple as checking the json object the api returns and looking at the "total results" number, then returning a specific message (at least I hope it's that simple).
Any and all help is appreciated!

HTML:
<form ng-submit="submitFunction()">
<input type="text" ng-model="movieTitle" placeholder="Search for a
movie">
<input type="submit" value="Submit">
</form>
CONTROLLER:
app.controller('MainController', ['$scope', '$http', function($scope, $http) {
$scope.submitFunction = function(){
$http.get('https://api.themoviedb.org/3/search/movie?api_key='+api_key+'&language=en-US&query='+$scope.movieTitle+'&page=1&include_adult=false')
.then(successCallback, errorCallback);
}
function successCallback(response){
$scope.movieList = response.data.results
}
function errorCallback(error){
}
}]);

Related

Angular TypeError: "Media.Search is not a function"

I know a similar question has been asked before, but I couldn't find a solution that worked for my situation, and maybe that comes down to my lack of experience in Angular, so if that's the case, I apologize in advance.
I'm building a pretty basic Angular App, it's just supposed to access the iTunes API and search for songs/movie/etc... and return a few results below. However, whenever I enter a character into the input, I get no results, and an error in the console(I'm using Firefox)
app.js
var app = angular.module('itunes-search', ['ngResource']).config(function($sceDelegateProvider){
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'https://itunes.apple.com/**'
]);
});
app.factory('Media', function($resource){
return $resource('https://itunes.apple.com/search?term=:query'),{query: '#query'}, {
search: {
method: 'JSONP',
params: {
limit: 3,
callback: 'JSON_CALLBACK'}
}
}
});
app.controller('MediaCtrl',
function($scope, Media){
$scope.query = '';
$scope.$watchCollection('query', function(){
if ($scope.query.length > 0){
Media.search({ query: $scope.query}, function(data){
$scope.results = data.results;
});
} else {
$scope.results=[];
}
});
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>iTunes Search</title>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.9/angular-resource.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="itunes-search" ng-controller="MediaCtrl">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="page-header">
<h1>iTunes Search</h1>
</div>
<input type="search" ng-model="query" ng-keyup="onKeyupSearch()"
placeholder="Search for Movies, Music, etc." style="width: 100%;"/>
<ul ng-repeat="result in results">
<span style="font-size:20px; margin-left:10px;">
<li>
<h2>{{result.trackName}}</h2>
<h3>{{result.artistName}}</h3>
<img ng-src="{{result.artworkUrl100}}"/>
</li>
</span>
</span>
</ul>
</div>
</div>
</body>
</html>
I hope I've given enough detail, and if you have any additional resources to help me learn more Angular, I'd really appreciate suggestions. I can add any additional information if I need to.
Thanks again!

Angularjs - Controller call init() function multiple times

I have a problem while I'm making an angularjs app.
I create a controller and bind it in routeProvider. With a function to initialize values for the controller like this.
angular.module('app.Login', ['app.rpc','ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/login', {
templateUrl: '/static/tour/app/login/login.html',
controller: 'loginController'
});
}])
.controller('loginController', function($scope, $location, rpc) {
$scope.init = function() {
$scope.error = "";
console.log("Login Initialized");
}
$scope.init();
});
for login.html like this
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1 class="page-header">Login</h1>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="alert alert-danger alert-dismissable" role="alert" ng-show="error">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<strong>Error: </strong>
<span>{{error}}</span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<form>
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" ng-model="username" placeholder="Username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" ng-model="password" placeholder="Password">
</div>
<button class="btn btn-primary action-btn" ng-click="login()">Login</button>
</form>
</div>
</div>
</div>
When I run the app, it call init() 3 times like this.
login
Find out in this stackoverflow that many people also get this troble. All of them solved by make sure that controller doesn't bind more than one time (in routProvider and in template), and check that only one ng-app in the template.
My main html like this.
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<title>Touring</title>
<!--Bootstrap-->
<link rel="stylesheet" href="/static/tour/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/tour/css/bootstrap-theme.min.css">
<!--/Bootstrap-->
</head>
<body>
<ng-view><ng-view>
<!--Angular-->
<script src="/static/tour/js/angular.min.js"></script>
<script src="/static/tour/js/angular-route.min.js"></script>
<script src="/static/tour/js/angular-cookies.min.js"></script>
<!--/Angular-->
<!--App-->
<script src="/static/tour/app/app.js"></script>
<script src="/static/tour/app/rpc/app-rpc.js"></script>
<script src="/static/tour/app/login/app-login.js"></script>
<script src="/static/tour/app/dashboard/app-dashboard.js"></script>
<script src="/static/tour/app/memo/app-memo.js"></script>
</body>
</html>
For my main app like this.
angular.module('app',
['ngCookies',
'ngRoute',
'app.Login',
'app.Dashboard',
'app.Memo',
])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
resolve: {
"check": function($cookies, $location) {
if(!$cookies.get("user_id")) {
$location.path("/login");
}
else {
$location.path("/dashboard");
}
}
}
})
.when('/logout', {
resolve: {
"check": function($cookies, $location) {
if($cookies.get("user_id")){
alert("You have been Logout");
}
$cookies.remove("user_name");
$cookies.remove("user_id");
$cookies.remove("token");
$cookies.remove("dbname");
$location.path("/login");
}
}
});
}]);
It ok for this controller, I just want to initialize a text but it's not ok for init in some controller that need some AJAX request to server side, could make too many request for noting. Anyone can solve this please help me. Thanks.
PS1. My practice base on angular-seed https://github.com/angular/angular-seed
PS2. At first, I also used jquery and it show WARNING: Tried to load angular more than once. Once I remove jquery it never show warning again, but it didn't fix my problem
I already solve it
<ng-view><ng-view>
use this instead
<div ng-view></div>
Concerning your multiple method call, are you sure your current URL is exactly the same as defined in the $routeProvider config? (maybe ngRoute redirects from /login/ to /login and calls your controller twice)
PS2. At first, I also used jquery and it show WARNING: Tried to load angular more than once. Once I remove jquery it never show warning again, but it didn't fix my problem
AngularJS already contains a lite version of jQuery: jqLite. If jQuery is loaded before Angular, this last one will use it. If not, it use the built-in lite version.
In your case, the error is probably due to a jQuery loading after the Angular loading. Angular already loads its version and you load it again.
Try to load jQuery before Angular or do not load it at all.

AngularJS "Controller as" in templates

I am new to AngularJS world and I am trying to setup a basic laravel/angular JWT auth following this tutorial.
What I'd like to do, it's to use the "Controller As" syntax instead of the $scope as stated in the tutorial. For now, here what I have:
app.js
var app = angular.module('app', ['ngRoute']);
app.run(function () {});
app.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/', {
templateUrl: 'js/templates/login.html',
controller: 'LoginController'
});
});
login controller
angular.module('app')
.controller('LoginController', function ($scope) {
this.title='toto';
this.data = {};
this.submit = function () {
console.log(this.data);
};
});
admin view
<!doctype html>
<html lang="en">
<head>
<title>Blog Administration</title>
<!--css-->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"/>
<!--js-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!--angular-->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/loginController.js"></script>
</head>
<body ng-app="app">
<div id="wrapper">
<div class="container" id="view" ng-view>
</div>
</div>
</body>
</html>
login template
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body ng-controller="LoginController as login">
<div class="container">
<div id="login" class="col-md-4 col-md-offset-4">
<div id="login-form">
<h4>{{ login.title }}</h4>
<form ng-submit="login.submit()"><!--username-->
<div class="form-group">
<input id="username" type="text" ng-model="login.data.username"/>
</div>
<!--password-->
<div class="form-group">
<input id="password" type="password" ng-model="login.data.password"/>
</div>
<!--submit-->
<div class="form-group">
<button class="btn btn-primary" type="submit">Login</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
The problem is that nothing renders. Is it possible to use a controller per template ?
If I put the <ng-controller="LoginController as login"> directive in the view body instead of template everything renders correctly.
Is it a good practice to define a controller per template ? Because the login template should be as generic as possible, so it can be loaded in any view if the user isn't authenticated, that's why I think putting login() action in the controlelr handling the Admin view is wrong.
Can someone advice me on the best practices to have here ?
In order to use controllerAs syntax with routeProvider you need to declare additional property in route configuration:
$routeProvider.when('/', {
templateUrl: 'js/templates/login.html',
controller: 'LoginController',
controllerAs: 'login'
});
Then you need to clean up login template, removing everything but actual template, e.g. no HTML, body tags, etc. You also don't need extra ngController directive in partial template:
<div id="login" class="col-md-4 col-md-offset-4">
<div id="login-form">
<h4>{{ login.title }}</h4>
<form ng-submit="login.submit()">
<!--username-->
<div class="form-group">
<input id="username" type="text" ng-model="login.data.username" />
</div>
<!--password-->
<div class="form-group">
<input id="password" type="password" ng-model="login.data.password" />
</div>
<!--submit-->
<div class="form-group">
<button class="btn btn-primary" type="submit">Login</button>
</div>
</form>
</div>
</div>
Question 1: Is it possible to use a controller per template ?
Ans: Yes. Its very simply. How, is shown in next answer.
Question 2: Is it a good practice to define a controller per template ?
Ans: As per the AngularJs shown rules, Its good practice. Now see the 2
different way of defining the controller for the template.
a. Directly into the template like: <div ng-controller="myCtrl">Whole template
data goes inside this div.</div>
b. from the app.js where we load the template like this:
.state('app.products.all', {
url: '/all',
templateUrl: 'tpl/products/blocks/thumb.html',
controller: 'ProductsAllCtrl'
})
Here i have also shown the controller with the template path. Second way is
more better then the first.

How to get angular app to access backend-API

So, Ive made a backend API for a todo-app Im working on, I know that http://localhost:3000/api/todo/done is working and returns two objects, looking like this:
[{"_id":"54d6485357a52fc640bb3814","text":"Hämta tårta","completed":true},{"_id":"54d648ae57a52fc640bb3815","text":"Köpa dricka till Antons kalas","completed":true}]
Ive now written a first attempt at a frontend in angular. It all runs well in node, with no errors but I do not get any todos listed in my todo-list div. Can you please advise on this?
HTML:
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script><!-- load jquery -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script><!-- load angular -->
<script src="../javascripts/core.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</script>
</head>
<body ng-controller"mainController">
<div class="container">
<!-- HEADER AND TODO COUNT -->
<div class="jumbotron text-center">
<h1>I'm a Todo-aholic <span class="label label-info">{{ todos.length }}</span></h1>
</div>
<!-- TODO LIST -->
<div id="todo-list" class="row">
<div class="col-sm-4 col-sm-offset-4">
<!-- LOOP OVER THE TODOS IN $scope.todos -->
<div class="checkbox" ng-repeat="todo in todos">
<label>
<input type="checkbox" ng-click="deleteTodo(todo._id)"> {{ todo.text }}
</label>
</div>
</div>
</div>
</body>
</html>
ANGULAR CODE:
var nodeTodo = angular.module('node-todo', []);
function mainController($scope, $http) {
$scope.formData = {};
// when landing on the page, get all todos and show them
$http.get('/api/todo/done')
.success(function(data) {
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
}
I dont even get anything printed in the console and I dont understand why...
Check if your angular app is correctly wired up. I don't see an ng-app directive in your html snippet and there is probably a typo in ng-contoller="mainController" (= is missing). Also your controller is not registered with module (but in this case it shouldn't make any difference).
Here is JSFiddle that at least shows error message when requesting data. Hope this helps to solve your problem
Try this in the html (note the ng-app atribute) to reference your module.
<body ng-app="node-todo">
<div class="container" ng-controller="mainController">
and then connect your controller to your app/module like this:
var nodeTodo = angular.module('node-todo', []);
nodeTodo.controller('mainController',
['$scope', '$http', function($scope, $http){
$scope.formData = {};
// when landing on the page, get all todos and show them
$http.get('/api/todo/done')
.success(function(data) {
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
}]);
Hope this helps.

Using ng-switch to swap templates

I'm trying to switch a "sign in" form for a "sign up" form whenever the user clicks on the "Sign Up" button in my angular app, but at the moment nothing is happening when the button is clicked; The sign in form remains on the screen and there are no console errors. Can anyone tell me where I'm going wrong?
I'm attempting to do this purely in html, is this even possible to achieve?
EDIT: I included a signup function in my UserCtrl which takes care of signing in/ out. Now when I click on sign up the alert is trigger but I get a console error saying TypeError: boolean is not a function.
$scope.signup = function() {
alert('signup function hit');
$scope.signup = true;
}
EDIT 2:
<!DOCTYPE html>
<html ng-app="myApp" >
<head>
<title> My App</title>
<link rel="stylesheet" type="text/css" href="css/app.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="css/signin.css">
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css" rel="stylesheet"/>
</head>
<body ng-controller="MainCtrl">
<div ng-switch on="view.name">
<div ng-switch-default ng-controller="UserCtrl">
<div ng-show="!isAuthenticated">
<form class = "form-signin">
<div class="control-group">
<img src="img/logo.png">
<br />
<div class="controls">
<br />
<input type="text" ng-model="username" placeholder = "Email Address" >
</div>
<br />
<div class="controls">
<input type="password" ng-model="password" placeholder = "Password" >
</div>
<div class="controls">
<button class = "btn btn-default" ng-click="signIn()">Sign In</button>
<button class = "btn btn-primary" ng-click="view.name = 'signup'">Register</button>
</div>
</div>
</form>
</div>
<div ng-switch-when="signup" ng-controller = "UserNewCtrl" >
<label>
This is where my form should be when my signup button is clicked.
</label>
</div>
//This part of index.html is only shown when a user has been authenticated
<div ng-show="isAuthenticated">
<div class="col-md-2">
//MenuBar code is here
</div>
//Other templates get loaded here
<div class="col-md-10">
<div ng-view></div>
</div>
</div>
</div>
<script src="js/vendor.js"></script>
<script src="js/app.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery-1.10.2.js"></script>
<script src="js/transition.js"></script>
<script src="js/ui-utils.js"></script>
</div>
</body>
</html>
MainCtrl.js:
angular.module('myApp.controllers')
.controller('MainCtrl', function($scope) {
$scope.view={
name: ''
};
})
To achieve your requirement you need a wrapper controller that hold ng-switch on model because ngSwitch creates child scope.
You can design your view like
<body ng-controller="mainCtrl">
<div ng-switch on="view.name">
<div ng-switch-default ng-controller="signInCtrl">
<h1>this is sign in page</h1>
sign in
<br>
go to sign up page
</div>
<div ng-switch-when="signup" ng-controller="signUpCtrl">
<h1>this is sign up page</h1>
sign up
<br>
go to sign in page
</div>
</div>
</body>
Here mainCtrl holds view.name and by default ng-switch-default works means your sign in page, then when you click
go to sign up page
view.name model changed and your sign-up page appear.
Check the Demo
move the app controller to the html tag, then the directive in your body tag should read if you want to match an expression
<html ng-app="myApp">
<body ng-switch="signup">
see here
where signup is a boolean in your myApp scope, that will presumably be changed when the signIn criteria is satisfactory
$rootScope.signup = true;
you can also achieve similar with the ng-show and ng-hide directives

Categories

Resources