AngularJS services running fine but not calling movies properly - javascript

I am making an API service with Rotten Tomatoes, and I am unable to see any movies that are being called. When I type in TOY it should return with movie titles that have the word toy within them. But, what I am getting now is grey-outline boxes whenever I search for the movies in my page. How can I make the movies appear on my page correctly? PS sorry for all of this code, it is showing you how my project is working.
Edit: I can't seem to get the slideToggle to work. Please help. Thanks!
Example is in the image:
http://i.stack.imgur.com/Ng0q3.png
Here is my code:
API.html
<div>
<img src="{{movie.posters.thumbnail}}" />
<h2>{{movie.title}}</h2>
</div>
<div>
<p>{{movie.synopsis}}</p>
<dl>
<dt>Rating</dt>
<dd>{{movie.mpaa_rating}}</dd>
<dt>Year</dt>
<dd>{{movie.year}}</dd>
<dt>Critics Score</dt>
<dd>{{movie.ratings.critics_score}}</dd>
<dt>Audience Score</dt>
<dd>{{movie.ratings.audience_score}}</dd>
<dt>Theater Release Date</dt>
<dd>{{movie.release_dates.theater}}</dd>
<dt>DVD Release Date</dt>
<dd>{{movie.release_dates.dvd}}</dd>
</dl>
</div>
apiController.js
module.exports = ApiController;
function ApiController($scope, movieLoader) {
$scope.data = {}
$scope.$watchGroup(['data.q', 'data.page_limit', 'data.page'], function() {
//Use movie loader
movieLoader.getMovies($scope.data.q, $scope.data.page_limit, $scope.data.page).then(function(response) {
$scope.movies = response.data.movies
});
})
}
apiDirective.js
module.exports = function() {
return {
restrict: 'EA',
templateUrl: 'api.html',
link: function(scope, element) {
//Dom manipulation
element.click(function() {
element.children('div').slideToggle();
});
}
};
};
apiFactory.js
module.exports = function apiFactory($http, apiUrl, apiKey) {
//Return object literal
return {
getMovies: function(q, page_limit, page) {
return $http.jsonp(apiUrl, {
params: {
q: q,
page_limit: page_limit,
page: page,
apikey: apiKey,
callback: 'JSON_CALLBACK'
}
});
}
}
}
index.html
<html ng-app="movieApp">
<head>
<title>demo</title>
<script src="bundle.js"></script>
<link href="styles.css" rel="stylesheet">
</head>
<body ng-controller="moviesController">
<!--Grab the title-->
<label for="q">Search Text</label>
<input type="text" id="q" ng-model="data.q" ng-model-options="{debounce: 500}"/>
<!--Define how many movies to place in the file-->
<label for="page_limit">Page Size</label>
<input type="text" id="page_limit" ng-model="data.page_limit" ng-model-options="{debounce: 500}"/>
<!--define what page to look at-->
<label for="page">Page Number</label>
<input type="text" id="page" ng-model="data.page" ng-model-options="{debounce: 500}"/>
<div class="movie" ng-repeat="movie in movies"></div>
</body>
</html>
directiveSearch.html
var jQuery = require('jQuery');
//We must make jquery global for Angular to use it
Window.jQuery = jQuery;
require('angular');
var apiFactory = require('./apiFactory');
var apiController = require('./apiController');
var apiDirective = require('./apiDirective');
angular.module('movieApp', [])
.factory('movieLoader', apiFactory)
.controller('moviesController', apiController)
.directive('movieDirective', apiDirective)
.constant('apiKey', 'Removed for security purposes')
.constant('apiUrl', 'http://api.rottentomatoes.com/api/public/v1.0/movies.json');

Related

Vue not working correctly with the html (refreshing when I press a button when it isn't supposed to)

I am having a problem where my vue doesn't work correctly.When I press the button it clears out the input(it shouldn't) and does nothing.The variables codigo and payload do not show anything in the screen. Even when I change them via console. It first was having the issue where the 'app' tag wasn't being found by the script even with it on the bottom. To solve it I had to add the line Vue.config.silent=true which made the warning disappear but the code still doesn't work. I am new to vue and web design so expect basic mistakes. I am running it in the 'node' docker image container.
<!DOCTYPE html>
<html>
<head>
<title>Vue test</title>
</head>
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js" ></script >
<script>
Vue.config.silent = true;
</script>
<body>
<h2>Manipulador de Recursos</h2>
<br>
<div id='app'>
<form>
URL do Recurso: <input type="text" v-model="recurso" size=50><br><br>
Repr. do Recurso: <input type="text" v-model="repr" size=100><br><br>
Metodo HTTP:
<button v-on:click="doGet">GET</button>
<button v-on:click="doPost">POST</button>
<button v-on:click="doPut">PUT</button>
<button v-on:click="doDelete">DELETE</button> <br><br><br>
</form>
<b>Retorno:</b><br><br>
Codigo HTTP: <span v-bind:id="codigo"></span>
<br><br>
Payload: <span v-html="payload"></span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script defer >
var myapp = new Vue({
el: "app",
data: {
"codigo":"",
"payload":"",
},
methods:{
// GET
"doGet" : function() {
console.log("GET")
this.clear();
var url = this.recurso;
axios
.get(url)
.then(function (response) {
this.codigo = response;
this.payload =response.data ;
console.log (response);
})
.catch(function (error){
this.codigo = error;
})
},
// POST
doPost : function() {
console.log("POST")
this.clear();
var url = this.recurso;
var data = this.repr;
axios
.post(url, data)
.then((response) => {
this.codigo = response;
this.payload =response.data ;
console.log(response)
})
.catch((error) => {
this.codigo = error;
})
},
//(...)
}
})
</script>
</html>
You don't want to prevent the click action, as suggested above, but the submit action of the form.
<form #submit.prevent="doGet()">
<!-- form stuff -->
</form>
At first, your methods must be inside methods property:
var myapp = new Vue({
//.......
data: {
codigo: "",
payload: ""
},
methods: {
doGet: function() { /*.......*/},
doPost: function() { /*.......*/}
}
})
and in this example your buttons can do default action (the form sending) so it may be necessary: v-on:click.prevent="doGet()".
This solved it Simple vue app doesn't show anything :
Because you didn't render anything in your root component.
In your index.html, render the app component:
<div id="app"> <app> <!-- html code, buttons etc--> </app> </div>
Adding the tags.
Along with this: adding type="button" to the buttons because since they where inside a forms they refreshed the page.
And finally I added:
document.addEventListener("DOMContentLoaded", function(event) {
Around my var myapp = new Vue({

editing data in local storage

I have a simple todo list for different topics which adds removes and edits data but when i am trying to edit the data from the local storage only the text displayed in the html is changing and not in the local storage. The edit is done by pressing on the edit button where a text box will show up to edit the data.
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script>
<script src="https://unpkg.com/vue-ls#2.3.3/dist/vue-ls.min.js"></script>
<title></title>
</head>
<body>
<div id="app">
<input type="text" v-model="todo.topic" placeholder="input todo"
v-on:keyup.enter="addTodo">
<ul>
<li v-for="(todo, index) in todos">
<input v-if="todo.edit" type="text" v-model="todo.topic">
<span v-else>{{todo.topic}} </span>
<button #click="removeTodo(index)">✖</button>
<button #click="todo.edit = !todo.edit">✎</button>
</li>
</ul>
</div>
<script>
Vue.use(VueLocalStorage);
new Vue({
el: '#app',
data(){
return {
todo: {
topic: null,
edit: false
},
todos: null || [],
}
},
watch: {
todos: function(val) {
this.$ls.set('todos', val)
}
},
mounted(){
this.todos = this.$ls.get('todos', this.todos);
var _this = this;
this.$ls.on('todos', function(val) {
_this.todos = val;
});
},
methods:{
addTodo(){
var vm = this;
vm.todos.push({topic:vm.todo.topic,edit: false });
vm.todo = []
},
removeTodo(index){
this.todos.splice(index, 1)
}
}
})
</script>
</body>
</html>
Seems you don't have an edit functionality on your code to edit todos.
I did some modification and added an edit function for it to work. You can check it out here: https://codesandbox.io/s/relaxed-cannon-tj7ef?fontsize=14. After clicking the edit icon, and editing, hit enter.
Here is my modification:
Modified the form in the todos loop:
<input
v-if="todo.edit"
type="text"
v-model="todo.topic"
v-on:keyup.enter="editTodo(todo.topic, index)"
/>
Added a function to edit todo:
editTodo(text, index) {
this.$set(this.todos, index, {
topic: text,
edit: false
});
},
You should change the key name of the local storage. it should be unique. I think it's better if you use vuex and not local storage.
But if you really want the local storage implementation you can do like this.
this.$ls.set('todos-id', val)
So that every local storage will be unique.

Access an element when the "Submit" button is clicked to get the values

So here's a great example from https://developer.forecast.io/docs/v2
What I want to do and trying is this:
I have a simply webpage whereby I want to display the current forecast and extended forecast.
Here's my Index.html
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html lang="en" class="no-js" ng-app="myApp">
<head>
<title>Weather Forecaster</title>
<meta charset="UTF-8">
<!-- favicon -->
<link rel="shortcut icon" href="images/Oxygen-Icons.org-Oxygen-Status-weather-clear.ico" />
<!-- END favicon -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<link href="css/jquery.jdigiclock.css" rel="stylesheet" type="text/css" />
<link href="css/wx-custom.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="js/jquery-1.12.2.js"></script>
</head>
<body ng-controller="wxController as ctrlWx">
<div class="container">
<div class="row">
<div class="col-10">
<div id="my-div" ng-model="myiFrame">
<iframe src="http://www.latlong.net/convert-address-to-lat-long.html" id="my-iframe" scrolling="no"></iframe>
</div>
<div id="plugin_container" class="forecast-panel">
<h1>Here's Today's Weather</h1>
<div class="fc forecast-panel1">
<p class="dayTitle">Day 1</p>
</div>
<div class="spacer"></div>
<div class="fc forecast-panel2">
<p class="dayTitle">Day 2</p>
</div>
<div class="spacer"></div>
<div class="fc forecast-panel3">
<p class="dayTitle">Day 3</p>
</div>
<div class="spacer"></div>
<div class="fc forecast-panel4">
<p class="dayTitle">Day 4</p>
</div>
<div class="spacer"></div>
<div class="fc forecast-panel5">
<p class="dayTitle">Day 5</p>
</div>
</div>
</div>
</div>
</div>
<script src="js/angular/angular.min.js" type="text/javascript"></script>
<script src="js/angular/app.js" type="text/javascript"></script>
<script src="js/angular/controller.js" type="text/javascript"></script>
<script src="js/angular/services.js" type="text/javascript"></script>
<script src="js/angular/ang-custom.js" type="text/javascript"></script>
</body>
</html>
Notice the "IFRAME".... the src is this: http://www.latlong.net/convert-address-to-lat-long.html
Now, if you go there, which is pretty cool, you can put ANY address to get the LAT LON for that address:
Here's a screen shot with an example LAT LON from DC... the Whitehouse.
OK, now, my code uses Angular with a simple controller and service...
Here:
APP:
/* global angular */
// Code goes here
var myApp;
myApp = angular.module("myApp", []);
myApp.config(function ($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist(['self', '**']);
});
console.log("Host name is: " + document.location.hostname);
//if (document.location.hostname === "localhost") {
// myApp.constant('URL', '/WeatherForecaster/js/json/');
//} else if (document.location.hostname === "omnimanger.co/wx" || "www.omnimanager.co/wx") {
// myApp.constant('URL', '/js/json/');
//} else {
// myApp.constant('URL', '/wx/js/json/');
//}
myApp.constant("URL", {
//Default LAT/LON for CONCRETE
apiKey: "3bb0f0fe93c92922f0b42f9eabda48d0/",
lat: "48.530031",
lon: ",-121.879460",
country: "us",
uri: "https://api.forecast.io/forecast/"
}).config(function($httpProvider){
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});;
myApp.constant("wx", {
data: {
latitude: 0,
longitude: 0,
currently: {},
minutely: {
summary: "",
icon: "",
data: []
},
hourly: {
summary: "",
icon: "",
data: []
},
daily: {
summary: "",
icon: "",
data: []
},
flags: {
sources: [],
"lamp-stations": [],
"isd-stations": [],
"madis-stations": [],
units: ""
}
}
});
CONTROLLER:
'use strict';
myApp.controller('wxController', function (wxDataService) {
var ctrlWx = this;
//Listen for the Submit (FIND) button on the iFrame
ctrlWx.content = {};
console.log("LAT/LON: ", ctrlWx.latlon);
ctrlWx.fetchWx = function () {
//General Data
wxDataService.getWxData().then(function (result) {
ctrlWx.content = result;
console.log("All Data: ", result);
});
};
ctrlWx.fetchWx();
});
SERVICE:
myApp.factory('wxDataService', function ($http, URL) {
console.log("URL", URL);
//DEFAULT Headers for KEY and AUTH TOKEN
var headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': ['GET', 'POST'],
'Access-Control-Allow-Headers': 'Content-Type',
'Content-Type': 'application/json'
};
var myURL = {
data: {
header: headers,
uri: URL.uri + URL.apiKey + URL.lat + URL.lon
}
};
var getWxData = function () {
return $http.get(myURL)
.success(function (data) {
console.log("SUCCESS!");
console.log("The Weather Data is here: " + data);
return data;
})
.error(function (e) {
console.log("He\'s dead Jim!<br>", e);
return e;
});
};
return {
getWxData: getWxData
};
});
SOLUTION I'm Trying to Achieve:
When the user enters the address and clicks the "FIND" button, which generates the LAT LON, I want to capture that LAT LON inside the IFRAME.
This is what I'm trying to do, but I know I need to make a directive that BINDS the "CLICK" or "SUBMIT" event to the FIND button. What I have below is NOT that; yet.
var latlon = {};
$(function () {
$('#my-iframe').load(function () {
$(this).contents().find("#latlongform, #gadres").live('blur', function (e) {
latlon = {
mylat: $("input[name='lat']").val(),
mylon: $("input[name='lon']").val()
};
if (e) {
console.log("Err: ", e);
return e;
}
});
});
});
GIVENS:
The FORM and the LAT LON are as follows:
<div class="row">
<div class="col-8 graybox">
<form id="latlongform">
<label for="gadres">Address</label>
<input id="gadres" type="text" class="width70" placeholder="Type address here to get lat long" required="">
<button title="Find lat long coordinates" class="button">Find</button><br>
<small>Write city name with country code for better results.</small>
</form>
<div class="row">
<div class="col-6 m2">
<label for="lat">Latitude</label>
<input type="text" name="lat" id="lat" placeholder="lat coordinate">
</div>
<div class="col-6 m2">
<label for="lng">Longitude</label>
<input type="text" name="lng" id="lng" placeholder="long coordinate">
</div>
</div>
</div>
</div>
QUESTION:
How can I get the LAT LON, "AFTER" the user clicks FIND, THEN fire my angular service to inject the CALL to the URL which gets the WEATHER DATA...as described. Here's that WEATHER DATA JSON OBJECT. It uses an API KEY which mine is limited to 1000 uses per day.
If you'd like to see what the result is on the weather API, you need to get a FREE API_KEY.... it gives 1000 hits per day...
Thanks everyone and I hope you can all this this is a VALID question.
Accessing the Forecast.io API with JSONP
The forecast.io website doesn't support CORS (Cross Origin Resource Sharing) for GET operations but it does support JSONP.
Revised Code
var url = myURL.data.uri;
var jsonpURL = url+"?callback=JSON_CALLBACK";
var getWxData = function () {
return $http.jsonp(jsonpURL)
.then(function (response) {
console.log("SUCCESS!");
console.log(response.data);
//return to chain data
return response.data;
})
.catch(function (e) {
console.log("He\'s dead Jim!");
console.log(e);
//throw to chain rejection
throw e;
});
};
Sample Result
LAT: 48.530031
LOG: -121.87946
TIMEZONE: America/Los_Angeles
SUMMARY: Partly Cloudy
TEMP: 56.02
The DEMO on JSFiddle.
Notice that I changed the .success and .error methods to .then and .catch respectively. Those old methods are deprecated and ignore return values.

Edit MEANJS list in the list page

I am using MEAN JS, i am trying to edit the list items on the list page, but it shows the error as below. i have initiated the data using ng-init="find()" for the list and ng-init="findOne()" for individual data.
Error: [$resource:badcfg] Error in resource configuration for action `get`. Expected response to contain an object but got an array
HTML
Below i the form inside the controller where it initiates the find() and findOne().
<div ng-controller="OrdersController" ng-init="find()">
<div>
<div class="order-filter">
<div ng-repeat="order in orders">
<form ng-init="findOne()" name="orderForm" class="form-horizontal" ng-submit="update(orderForm.$valid)" novalidate>
<input type="text" class="" ng-model="order.title">
<input type="text" class="" ng-model="order.content">
<div class="form-group">
<input type="submit" value="Update" class="btn btn-default">
</div>
</form>
</div>
</div>
</div>
</div>
Controller
$scope.update = function (isValid) {
$scope.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'orderForm');
return false;
}
var order = $scope.order;
order.$update(function () {
$location.path('orders/' + order._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.find = function () {
Orders.query(function loadedOrders(orders) {
orders.forEach(appendFood);
$scope.orders = orders;
});
};
$scope.findOne = function () {
$scope.order = Orders.get({
orderId: $stateParams.orderId
});
};
You need to check your Orders Service which probably is using $resource to provide your API requests (Orders.query)
It should look something like this:
function OrdersService($resource) {
return $resource('api/orders/:orderId', {
orderId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
The style may be different depending on which version of mean you're using. By default, the $resource query will expect an array of results, but if for some reason you've set "isArray" to false then it will expect an object.
https://docs.angularjs.org/api/ngResource/service/$resource

Add new input to dynamic nested list in AngularJS

On my page I have a dynamic list of musicians (players) whereas a player can be removed and added to the list. Each player shall have multiple instruments which is also a dynamic list, whereas an instrument can be added or removed from a player's instrument list. So we are talking about two nested dynamic lists.
Here is the code and the problem description under it.
jamorg.html:
<!DOCTYPE html>
<html ng-app='jamorgApp'>
<head>
<link rel="stylesheet" type="text/css" href="C:\Users\jazzblue\Documents\Bootstrap\bootstrap-3.3.2-dist\css\bootstrap.min.css" />
<title>Jam Organizer</title>
</head>
<body>
<div ng-controller='JamOrgController as jamOrg'>
<h1>Jam</h1>
<div ng-repeat='player in players'>
<div>
<h3 style="display: inline-block;">player {{$index}}</h3>
<button ng-click="removePlayer($index)">Remove</button>
</div>
<br/>
<div ng-controller='JamOrgPlayerController as jamOrgPlayer'>
<div ng-repeat='instrument in player'>
<span>Instrument: {{instrument.instrument}},</span>
<span>Level: {{instrument.level}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
<button ng-click="addInstrument()">Add Instrument</button>
Instrument: <input ng-model='newInstrument.instrument'>
Level: <input ng-model='newPlayer.level'>
</div>
</div>
</div>
<script type="text/javascript" src="C:\Users\jazzblue\Documents\AngularJS\angular.min.js"></script>
<script type="text/javascript" src="jamorgApp.js"></script>
</body>
</html>
jamorgApp.js
var app = angular.module('jamorgApp', []);
app.controller('JamOrgController', ['$scope', function($scope){
$scope.players = players;
$scope.removePlayer = function(index) {
$scope.players.splice(index, 1);
}
}]);
app.controller('JamOrgPlayerController', ['$scope', function($scope){
$scope.newInstrument = newInstrument;
$scope.remove = function(index) {
$scope.player.splice(index, 1);
}
$scope.addInstrument = function() {
$scope.player.push(newInstrument);
}
}]);
var players = [
[{instrument: 'Guitar', level: 3}, {instrument: 'Keyboard', level: 3}],
[{instrument: 'Bass', level: 4}],
[{instrument: 'Drums', level: 3}]
];
var newInstrument = [
{instrument: 'x', level: 'y'}
]
Here is my problem: the same newInstrument is being added to all the different players lists which is wrong: each player's instrument list should have its own newInstrument.
How should I change it to get the right design?
Thanks!
Where you do:
$scope.addInstrument = function() {
$scope.player.push(newInstrument);
}
Try doing:
$scope.addInstrument = function() {
$scope.player.push(angular.copy(newInstrument));
}
Update:
In your HTML:
<button ng-click="addInstrument(player)">Add Instrument</button>
In your JS:
$scope.addInstrument = function(player) {
player.push(angular.copy(newInstrument));
}
UPDATE
I created a fiddle where you can check some possible modifications to your code. It uses just one controller and fixes the duplicated object issues.
<button ng-click="addInstrument($index)">Add Instrument</button>
Instrument: <input ng-model='newInstrument.instrument'>
Level: <input ng-model='newPlayer.level'>
and your addInstrument function should be like this
$scope.addInstrument = function(index) {
$scope.players[index].push($scope.newInstrument);
}

Categories

Resources