angularjs. Display object property after http.get - javascript

I am new to Angular.js and i did the tutorial Shaping up with angularjs in codeschool.com so please forgive me if the problem i am trying to solve might be too easy to resolve.
So, i am just trying to show a data i get from $http.get() which is JSON object into my document.
index.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>League of legends</title>
<!-- Load StyleSheets -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<!-- Load Javascript Libraries -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/angular.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-app="LeagueOfLegends">
<!-- Navbar menu -->
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li>
About
</li>
<li>
Contact
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div ng-controller="searchSummoner as summoner">
<!-- Search Form -->
<div ng-show="summoner.status.showSearch">
<form ng-submit="summoner.search()">
<div class="well">
<div class="form-group">
<label for="summonerName">Summoner Name</label>
<input type="text" class="form-control" placeholder="Enter Summoner Name" id="summonerName" ng-model="summoner.form.name">
</div>
<div class="form-group">
<label ng-repeat="region in summoner.region">
<input type="radio" ng-model="summoner.form.region" ng-value="region">{{region}}
</label>
</div>
<input type="submit" class="btn btn-default" value="Search"></input>
</div>
</form>
</div>
<p ng-show="summoner.status.showResult">Get request from: {{summoner.data.name}}</p>
</div>
</div>
</body>
app.js (module-controller):
var app = angular.module('LeagueOfLegends', []);
app.controller('searchSummoner', ['$http', function($http)
{
var form = {};
this.data = {};
this.form = {};
this.status = {
showSearch: true,
showResult: false
};
this.region = ['br', 'eune', 'euw', 'lan', 'las', 'na', 'oce', 'kr', 'tr'];
this.search = function()
{
form = this.form;
this.form = {};
// get data from the api rest
$http.get(getApiUrl(form)).success(function(data){
this.data = data[form.name];
console.log(this.data);
});
// hide form
this.status.showSearch = false;
this.status.showResult = true;
};
}]);
function getApiUrl(form)
{
var apiKey = 'fe9eb24f-5800-4f2a-b570-15328062b341';
return 'https://lan.api.pvp.net/api/lol/' + form.region + '/v1.4/summoner/by-name/' + form.name + '?api_key=fe9eb24f-5800-4f2a-b570-15328062b341'
}
after $http.get was successfully made, i make a log just to check if the data i retrieve is the one i need, but it does not show the object property in html

You're using this in the wrong closure. This is what you should do :
var that = this;//give controller scope access
// get data from the api rest
$http.get(getApiUrl(form)).success(function(data){
that.data = data[form.name];
console.log(that.data);
});

You could also bind your context like this:
$http.get(getApiUrl(form)).success(function(data){
this.data = data[form.name];
console.log(this.data);
}.bind(this));
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Related

Javascript: Unable to access response object and dynamically generated html elements outside the function

I am creating a todo app with Django + Ajax. On load I am loading all the tasks from the db and displaying it and when user clicks on any task i want to mark it as completed. The problems i am facing are
I am unable to access the dynamically generated html elements and
the response object, outside the buildList() function.
When i add event listener to a task (span element with class = title) i am unable to access the task object so i can send it to backend using ajax request and work with it.
todo.js
buildList()
function buildList(){
var wrapper = document.querySelector("#list-wrapper")
wrapper.innerHTML = ''
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8000/api/task-list/', true)
xhr.onload = function(){
if(this.status==200){
var list = JSON.parse(this.response)
for (var i in list){
var item = `
<div id="data-row-${i}", class="task-wrapper flex-wrapper">
<div style="flex:7">
<span class="title">${list[i].title}</span>
</div>
<div style="flex:1">
<button class="btn btn-sm btn-outline-info edit">Edit</button>
</div>
<div style="flex:1">
<button class="btn btn-sm btn-outline-dark delete">-</button>
</div>
</div>
`
wrapper.innerHTML += item
}
for(i in list){
var tasks = document.querySelectorAll('.title')
tasks.forEach(function(el, list){
el.addEventListener('click',()=>{
console.log(list[i])
})
})
}
}
}
xhr.send()
}
// Addding a Task //
var form = document.querySelector("form")
form.addEventListener('submit', (e)=>{
e.preventDefault()
var title = document.getElementById('title').value
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://127.0.0.1:8000/api/task-create/', true)
xhr.setRequestHeader('Content-type','application/json')
xhr.setRequestHeader('X-CSRFToken',csrftoken)
xhr.onload = function(){
if(this.status==200){
buildList()
document.getElementById('form').reset()
}
}
xhr.send(JSON.stringify({"title":title}))
}
)
// Marking a task as complete //
function taskComplete(e){
console.log(e.target)
}
index.html
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{% static 'styles.css' %}">
<title>To Do</title>
</head>
<body>
<div class="container">
<div id="task-container">
<div id="form-wrapper">
<form id="form">
<div class="flex-wrapper">
<div style="flex: 6">
<input id="title" class="form-control" type="text" name="title" placeholder="Add task">
</div>
<div style="flex: 1">
<input id="submit" class="btn" type="submit" >
</div>
</div>
</form>
</div>
<div id="list-wrapper">
</div>
</div>
</div>
</body>
<script src="{% static 'todo.js' %}"></script>
</html>
It looks like when you add the event listener you want to access a variable named list with your fetched data, however in that lexical scope list is being assigned to a callback argument. My suggestion is to rename the callback argument. Then you can access list from the parent scope.
tasks.forEach(function(el, index){

KO "click" binding won't work for mobile device responsive

I am trying to create a responsive one page web application. On clicking the list of items on the side bar you the markers and on the map should animate and display info window. It seems to be working perfect on normal browser layout but when I toggle display to smaller screens or on a mobile device, The click function does not work. The logic seems to be correct. Please help me understand where I am going wrong and what I should do. Thank you.
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link href="style.css" rel="stylesheet">
<script src="js/jquery-3.2.1.js"></script>
<script src="js/knockout-3.4.0.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div id="sidebar" class="col-xs-12 col-sm-5 col-md-3">
<h1 class="center" > Chennai City Culture </h1>
<div class="input-group col-xs-12 col-sm-6 col-md-12" >
<input id="text-search" type="text" class="form-control" placeholder="Enter here" data-bind="textInput: query">
</div>
<div class= "list-box" data-bind="foreach: filteredItems">
<hr>
</div>
</div>
<div class="col-xs-16 col-sm-6 col-md-8">
<div id="map">
</div>
</div>
</div>
</div>
<script src="js/app.js"></script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBf9eFadPLrD3QIQT7ygrYN8aRO5YuAUyE&callback=initMap" onerror="error()">
</script>
</body>
</html>
JS:
function appViewModel(){
var self = this;
this.query = ko.observable('');
this.locationArray = ko.observableArray([]);
locations.forEach(function(item){
self.locationArray().push(item);
});
self.setLoc = function(clickedLoc) {
var clickedData = clickedLoc.marker;
google.maps.event.trigger(clickedData, 'click');
};
self.filteredItems = ko.computed(function(){
var filter = self.query().toLowerCase();
if(!filter){
for (i = 0; i < locations.length; i++) {
if (locations[i].marker) //checks to see that markers exist
locations[i].marker.setVisible(true);
}
return self.locationArray();
}
return this.locationArray().filter(function (item){
var passedFilter = item.title.toLowerCase().indexOf(filter) > -1;
item.marker.setVisible(passedFilter);
return passedFilter;
});
}, self);
}
ko.applyBindings(new appViewModel());
click events aren't the same as touch events; try including a library like touchpunch that will handle those events for you for mobile devices. I had the same issue with a KO app I was building and that seemed to solve it.

How to push element in array of JSON

This is my controller from which I am requesting to POST the data on server. While I am able to POST title and rating, i am unable to POST any genres because Genres is an array. How to push the data in Genres Array?
app.controller('addTrack', function ($scope, $http) {
$scope.tracks = [];
var genre = [];
var pushing = genre.push($scope.add_genre);
$scope.add_track = "";
$http.get('http://104.197.128.152:8000/v1/tracks?page=48')
.then(function (response) {
$scope.tracks = response.data.results;
});
$scope.add = function (event) {
if (event.keyCode == 13) {
$http.post('http://104.197.128.152:8000/v1/tracks', {
title: $scope.add_title,
rating: $scope.add_rating,
})
.then(function (data) {
$scope.genres = data;
//console.log($scope.add_genre);
$scope.add_title = '';
$scope.add_rating = '';
$scope.add_genre = '';
});
$http.get('http://104.197.128.152:8000/v1/tracks?page=48')
.then(function (response) {
$scope.genres = response.data.results;
});
}
} });
Http POST to http://104.197.128.152:8000/v1/tracks
Accepted response
{
"title": "animals",
"rating": 4.5,
"genres": [
1
]
}
Providing you my HTML as well.
<!DOCTYPE html>
<html ng-app="musicApp">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container" ng-controller="addTrack">
<div>
<h1>Add New Track</h1>
</div>
<div class="form-group">
<label>Title:</label>
<input type="text" class="form-control" ng-model="add_title" placeholder="Type to add new Title">
</div>
<div class="form-group">
<label>Genre:</label>
<input type="text" class="form-control" ng-model="add_genre" placeholder="Type to add new Genre">
</div>
<div class="form-group">
<label>Rating:</label>
<input type="text" class="form-control" ng-model="add_rating" placeholder="Type to add new Rating" ng-keyup="add($event)">
</div>
<div class="clearfix">
<button class="btn btn-primary col-xs-12 bottom-button" value="click" id="button">Add a New Track</button>
</div>
<div class="clearfix">
<label>Available Tracks</label>
<ul class="list-group" ng-repeat="track in tracks">
<li class="list-group-item clearfix"><span class="pull-left title">{{track.title}}</span> <span class="genre">[{{track.genres[0].name}}]</span> <span class="pull-right rating">{{track.rating}}</span></li>
</ul>
</div>
</div>
</body>
</html>
If what you are trying to achieve is to add a track object with title, rating and genre, you need to change your whole logic so your controller will bind all inputs to the same object properties.
First you need to define a track object in your controller, and bind the inputs to its properties in your HTML:
JavaScript:
app.controller('addTrack', function($scope, $http) {
$scope.tracks = [];
$scope.track = {
title: '',
rating: 0,
genre: ''
};
$http.get('http://104.197.128.152:8000/v1/tracks?page=48')
.then(function(response) {
$scope.tracks = response.data.results;
});
$scope.add = function(event) {
if (event.keyCode == 13) {
$http.post('http://104.197.128.152:8000/v1/tracks', $scope.track)
.then(function(data) {
$scope.track = {};
});
}
}
});
HTML:
<!DOCTYPE html>
<html ng-app="musicApp">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container" ng-controller="addTrack">
<div>
<h1>Add New Track</h1>
</div>
<div class="form-group">
<label>Title:</label>
<input type="text" class="form-control" ng-model="track.title" placeholder="Type to add new Title">
</div>
<div class="form-group">
<label>Genre:</label>
<input type="text" class="form-control" ng-model="track.genre" placeholder="Type to add new Genre">
</div>
<div class="form-group">
<label>Rating:</label>
<input type="text" class="form-control" ng-model="track.rating" placeholder="Type to add new Rating" ng-keyup="add($event)">
</div>
<div class="clearfix">
<button class="btn btn-primary col-xs-12 bottom-button" value="click" id="button">Add a New Track</button>
</div>
</div>
</body>
</html>
Note:
Note the use of ng-model="track.title", ng-model="track.rating"
and ng-model="track.genre" in the HTML to bind these inputs to our
trackobject properties.
This code assumes that genre will be a string here, if you will use a
list of object you need to amend your code so it fits this option.

Laravel + AngularJS controller is existing but returns an error of not a function

Im just new to AngularJS and would like to integrate it using Laravel (5.2)
I was able to successfully load Laravel and Angular in this manner.
HTML File: ../resources/views/master.php
<!DOCTYPE html>
<html>
<head>
<title>...</title>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script type="text/javascript" src="assets/js/phone-app/app.module.js"></script>
</head>
<body>
<div class="container" ng-app="todoApp">
<div class="row">
<div class="col-md-12">
<h2>Todo</h2>
<div ng-controller="TodoListController as todoList">
<span>{{todoList.remaining()}} of {{todoList.todos.length}} remaining</span>
[ archive ]
<ul class="unstyled">
<li ng-repeat="todo in todoList.todos">
<label class="checkbox">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</label>
</li>
</ul>
<form ng-submit="todoList.addTodo()">
<input type="text" ng-model="todoList.todoText" size="30" placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
</div>
</div>
</div>
</body>
</html>
AngularJS File: ../public/assets/js/phone-app/app.module.js
(function() {
'use strict';
angular.module('todoApp', [])
.controller('TodoListController', function() {
var todoList = this;
todoList.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}];
todoList.addTodo = function() {
todoList.todos.push({text:todoList.todoText, done:false});
todoList.todoText = '';
};
todoList.remaining = function() {
var count = 0;
angular.forEach(todoList.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
todoList.archive = function() {
var oldTodos = todoList.todos;
todoList.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) todoList.todos.push(todo);
});
};
});
})();
But when I created a separate html that will accommodate angular templates, this is when I get an error of Argument 'TodoListController' is not a function, got undefined
Here's the structure:
HTML File: ../resources/views/master.php
<!DOCTYPE html>
<html>
<head>
<title>...</title>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script type="text/javascript" src="assets/js/phone-app/app.module.js"></script>
</head>
<body>
<div class="container" ng-app="todoApp">
<div class="row">
<div class="col-md-12">
<todo-app></todo-app>
</div>
</div>
</div>
</body>
</html>
AngularJS File: ../public/assets/js/phone-app/app.module.js
(function() {
'use strict';
angular.module('todoApp', []);
angular.module('todoApp')
.component('todoApp', {
templateUrl: 'assets/js/phone-app/templates/todo.html',
controller: function TodoListController() {
var todoList = this;
todoList.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}];
todoList.addTodo = function() {
todoList.todos.push({text:todoList.todoText, done:false});
todoList.todoText = '';
};
todoList.remaining = function() {
var count = 0;
angular.forEach(todoList.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
todoList.archive = function() {
var oldTodos = todoList.todos;
todoList.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) todoList.todos.push(todo);
});
};
}
}
);
})();
Template File: ../public/assets/js/phone-app/templates/todo.html
<h2>Todo</h2>
<div ng-controller="TodoListController as todoList">
<span>{{todoList.remaining()}} of {{todoList.todos.length}} remaining</span>
[ archive ]
<ul class="unstyled">
<li ng-repeat="todo in todoList.todos">
<label class="checkbox">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</label>
</li>
</ul>
<form ng-submit="todoList.addTodo()">
<input type="text" ng-model="todoList.todoText" size="30" placeholder="add new todo here">
<input class="btn btn-primary" type="submit" value="add">
</form>
</div>
If you'll notice, I moved the content on a separate template file. This loads the page with the template but returns an error on the console and just displays the page as is.
I was able to get this work but somehow don't know how this works. #_#
Anyway, I just tried to search for examples on the AngularJS site and tried to "copy" them. With that, I have arrived with this solution.
On the template file, I removed the ng-controller and change all the todoList with $ctrl.
<h2>Todo</h2>
<div>
<span>{{$ctrl.remaining()}} of {{$ctrl.todos.length}} remaining</span>
[ archive ]
<ul class="unstyled">
<li ng-repeat="todo in $ctrl.todos">
<label class="checkbox">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</label>
</li>
</ul>
<form ng-submit="$ctrl.addTodo()">
<input type="text" ng-model="$ctrl.todoText" size="30" placeholder="add new todo here">
<input class="btn btn-primary" type="submit" value="add">
</form>
</div>
Will someone please explain to me how did the $ctrl worked in here and why the ng-controller is not necessary in this kind of structure versus the first one I stated above?
Try to replace
.component
with
.directive
Maybe components have a bug

uncaught type error: undefined is not a function

Im making a simple form with Telerik Appbuilder HTML5 + javascript that takes a users input and logs it to the console when they click the submit button.
ClientClass.js:
function Client() {
this.username = "username",
this.password = "Password",
this.printUsername = function() {
this.username=$("#Username").val()
console.log(this.username);
};
};
Home.html:
<div data-role="view" data-title="Login" data-layout="main" data-model="APP.models.login">
<script src="../scripts/ClientClass.js"></script>
<h1 data-bind="html: title"></h1>
<script src="../scripts/ClientClass.js"></script>
<script>
function printUsername() {
var client = new client();
client.printUsername();
}
</script>
<ul data-role="listview" data-style="inset">
<li>
<label>Username
<input type="text" value="" id="Username" />
</label>
</li>
<li>
<label>Password
<input type="password" value="" />
</label>
</li>
<li>
<label>
<button onclick="printUsername()" type="button">Submit</button>
</label>
</li>
</ul>
</div>
Index.html:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<link href="kendo/styles/kendo.mobile.all.min.css" rel="stylesheet" />
<link href="styles/main.css" rel="stylesheet" />
<script src="cordova.js"></script>
<script src="kendo/js/jquery.min.js"></script>
<script src="kendo/js/kendo.mobile.min.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/ClientClass.js"></script>
</head>
<body>
<script src="scripts/ClientClass.js"></script>
<script src="scripts/ClientClass.js"></script>
<div data-role="layout" data-id="main">
<div data-role="header">
<div data-role="navbar">
<span data-role="view-title"></span>
</div>
</div>
<!-- application views will be rendered here -->
<label>
<input type="password" value="password" />
</label>
<div data-role="footer">
<div data-role="tabstrip">
Home
Settings
Contacts
</div>
</div>
</div>
</body>
</html>
It says in the console:
uncaught type error: undefined is not a function.
Then it says it is at index.html#views/home.html:1 and when I click that and it takes me to sources panel of the debugger. And it says the source is index.html and it says:
(function() {with (this[2]) {with (this[1]) {with (this[0]) {return function(event) {printUsername() }; }}}})
Does anyone see any issues with my html or javascript? Or the way I import the script? Thanks
you are declaring your client as an object, not as a "class". So using new on your object doesn't make quite sense.
So it's up to you or you keep your object and simply remove:
var client = new client();
or you use a class
function Client(){}

Categories