How to Query a JSON file using Angular/Ionic? - json

I'm trying to have Angular query a JSON file instead of using an http request in an Ionic project.
I'm working with the Ionic tutorial found here: https://ccoenraets.github.io/ionic-tutorial/index.html
I have gone through the entire tutorial and am "tinkering" which started with me wanting to change the data source from being an http request to a local JSON file and I've been partially successful.
All of the code I have in the project matches exactly what's seen in the tutorial with the following exception.
In the tutorial on "Module 4: Creating the Session Service," I changed this block seen in Step 3:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('http://localhost:5000/sessions/:sessionId');
});
To be:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json');
});
To create the JSON file I took the return value of the http request seen in the tutorial and pasted it into the file referenced in the code and it is valid JSON.
Now, when I run the project (in a desktop browser or emulator), I am able to see the list of Sessions that was read from the JSON as expected. However, when I click/tap one of the Sessions to see the detail, the UI appears but has no data. When using the original code that gets the data via http I can see the detail.
This is the controller in my code that matches the tutorial, which presumably is where the problem lies:
.controller('SessionCtrl', function($scope, $stateParams, Session) {
$scope.session = Session.get({sessionId: $stateParams.sessionId});
})
Here is the HTML for that view:
<ion-view view-title="Session">
<ion-content>
<div class="list card">
<div class="item">
<h3>{{session.time}}</h3>
<h2>{{session.title}}</h2>
<p>{{session.speaker}}</p>
</div>
<div class="item item-body">
<p>{{session.description}}</p>
</div>
<div class="item tabs tabs-secondary tabs-icon-left">
<a class="tab-item">
<i class="icon ion-thumbsup"></i>
Like
</a>
<a class="tab-item">
<i class="icon ion-chatbox"></i>
Comment
</a>
<a class="tab-item">
<i class="icon ion-share"></i>
Share
</a>
</div>
</div>
</ion-content>
</ion-view>
Here is the error in the console after clicking through to the Session detail view:
Error: [$resource:badcfg] get
http://errors.angularjs.org/1.3.13/$resource/badcfg?p0=object&p1=array
at REGEX_STRING_REGEXP (http://localhost:8100/lib/ionic/js/ionic.bundle.js:8762:12)
at d.module.provider.$get.e.(anonymous function).q.then.p.$resolved (http://localhost:8100/lib/ionic/js/angular/angular-resource.min.js:9:330)
at processQueue (http://localhost:8100/lib/ionic/js/ionic.bundle.js:21888:27)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:21904:27
at Scope.$get.Scope.$eval (http://localhost:8100/lib/ionic/js/ionic.bundle.js:23100:28)
at Scope.$get.Scope.$digest (http://localhost:8100/lib/ionic/js/ionic.bundle.js:22916:31)
at Scope.$get.Scope.$apply (http://localhost:8100/lib/ionic/js/ionic.bundle.js:23205:24)
at done (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18358:47)
at completeRequest (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18548:7)
at XMLHttpRequest.requestLoaded (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18489:9)
And here's the data where the Session list comes from and it's also the data I want to query:
[{"id":0,"title":"Introduction to Ionic","speaker":"CHRISTOPHE COENRAETS","time":"9:40am","room":"Ballroom A","description":"In this session, you'll learn how to build a native-like mobile application using the Ionic Framework, AngularJS, and Cordova."},{"id":1,"title":"AngularJS in 50 Minutes","speaker":"LISA SMITH","time":"10:10am","room":"Ballroom B","description":"In this session, you'll learn everything you need to know to start building next-gen JavaScript applications using AngularJS."},{"id":2,"title":"Contributing to Apache Cordova","speaker":"JOHN SMITH","time":"11:10am","room":"Ballroom A","description":"In this session, John will tell you all you need to know to start contributing to Apache Cordova and become an Open Source Rock Star."},{"id":3,"title":"Mobile Performance Techniques","speaker":"JESSICA WONG","time":"3:10Pm","room":"Ballroom B","description":"In this session, you will learn performance techniques to speed up your mobile application."},{"id":4,"title":"Building Modular Applications","speaker":"LAURA TAYLOR","time":"2:00pm","room":"Ballroom A","description":"Join Laura to learn different approaches to build modular JavaScript applications."}]
I can't seem to get my head wrapped around why changing the http request to a local file does not work for the query performed in 'SessionCtrl'.
What changes need to be made so the detail view will work?
UPDATE
Following the suggestion from #ErnestoRendon I think I have made progress.
I changed the factory to look like this:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
And the controller has been updated to look like this:
.controller('SessionCtrl', function($scope, $stateParams, Session) {
$scope.session = Session.getData({sessionId : $stateParams.sessionId});
console.log($stateParams.sessionId); // This DOES log the correct option selected from the list
})
When leaving isArray set to false I get the same object/array error when getData() is called. When I change isArray to "true" the error goes away but no data is returned to the UI. This is the error when setting that value to "false": http://errors.angularjs.org/1.3.13/$resource/badcfg?p0=object&p1=array
In either scenario (isArray being "true" or "false") the correct sessionId will log to the console from the controller.
So while things appear to be better when setting isArray to "true," I'm still not getting data into the UI.

Here's an example that loads data from a JSON file similar to what you describe.
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
Notice that isArray is set to false.

Related

Getting Google Maps to load in meteor project

I am have an issue of getting my meteor project to display a map. I am using dburles as my googleapi library. I have followed the instructions in the tutorial and my GoogleMaps.load() returns undefined, which is what I think is the underlying issue.
Meteor.startup ->
GoogleMaps.load()
console.log GoogleMaps.load()
return
My jade looks like such
div#search-wrapper
h2 Search for a ATM
div#search-input.input-group
input(for="search" type="text" placeholder="City, State, Zip, ect")
div.input-group-append
button(type="submit" class="btn btn-info " id="search-button")
i.fas.fa-search
button(type="submit" class="btn btn-info" id="find-nearMe") Find Near Me
+map
template(name="map")
div.map-container
googleMap(name="map" options=mapOptions)
I know coffeescript and jade are not widely used so answers in Javascript would be acceptable also please.
that library has no recent update. It comes from a time when NPM was a hack in Meteor.
You could try to amend this ES6 code to your liking (with your own google key). Call this function on load of the screen where you actually need a map. You can call it multiple times from multiple pages as the function checks if maps are present or not. You don't want to have this in Startup unless maybe you display a map on your first screen but then again, you would call the function at the component/view level.
const loadGoogleMaps = () => {
if (!window.google?.maps) {
const script = document.createElement('script')
script.src = 'https://maps.googleapis.com/maps/api/js?key=xxxxxx&libraries=places'
script.defer = true
document.head.appendChild(script)
}
}
export { loadGoogleMaps }
Another option would be indeed to use the official NPM (https://www.npmjs.com/package/#googlemaps/google-maps-services-js).

Interfacing with Spring boot Database using Heroku custom domain

Currently in the ending stages of trying to get my app online. However using the custom domain, which is on a standard goDaddy Account, I cant view any of my tables
$http.get("https://HEROKU DOMAIN/chat").then(function (response){
$scope.chats = response.data;
});
$scope.postchat = function(chatMsg){
var data = {
chatMsg: chatMsg
};
$http.post("https://HEROKU DOMAIN/chat", JSON.stringify(data))
location.reload();
};
});
This is the AngularJs code . I've tried getting and posting from the Heroku domain, the custom domain and the dns target with no avail. Everything works on my Heroku domain, but on the custom domain no data shows up, and I cant post any data. Here is the front end html code if anyone is interested
<div class="div1">
<table class="table table2">
<tr><th>Messages</th></tr>
<tr ng-repeat="chat in chats">
<td>{{chat.chatMsg}}</td>
</tr>
</table>
Chat <input ng-model="chatMsg"/>
<button class="button button2" ng-click="postchat(chatMsg)">Send</button>
</div>
I'm not sure where to go from here, there might be some security that my custom domain has in regards to who can post and who can get from it. However, as I understand it my custom domain is merely pointing to my heroku app.
Turns out if you use http instead of https while using the custom domain everything works.
$http.get("http://CUSTOM DOMAIN/chat").then(function (response){
$scope.chats = response.data;
});
$scope.postchat = function(chatMsg){
var data = {
chatMsg: chatMsg
};
$http.post("http://CUSTOM DOMAIN/chat", JSON.stringify(data))
location.reload();
};
});

Data from AngularJS local storage service not rendering unless page refreshed

I am building a small AngularJS project and I have encountered a problem that I want to ask you guys about.
I am using angular-local-storage module to store some data coming from my API into the browser's local storage.
In one of my controllers I assign this data to a variable in the $scope object and try to render it in the view as follows:
controller:
angular.module('Dashboard')
.controller('DashboardController',
['$scope', '$rootScope', 'localStorageService',
function ($scope, $rootScope, localStorageService) {
$scope.userData = localStorageService.get('userData');
}]);
And the view:
<div class="row">
<h4>Welcome to your dashboard <strong>{{userData.personalUserInfo.name}}</strong>!</h4>
When I log into the app (which is when the data is fetched from API and stored in local store by key 'userData'), the view is incomplete, I get only "Welcome to your dashboard !" without the name there. When I go to the dev console and look at the localStorage of my browser, the entry "userData" is there, it is just not rendered.
Then when I hit F5 and refresh the page, the name appears.
Do you have any ideas why that is and what can be done to fix that?
Cheers!
You have to use $scope.$watch for this, like following:
$scope.$watch(function() {
return localStorageService.get('userData');
}, function(newVal, oldVal) {
if (newVal !== oldVal)
$scope.userData = newVal;
})
$scope.$watch, will execute second function each time return value of first function is changed.

Ionic getting remote JSON data

I tried the following code by coping the data from JSON link as an object. Everything was good. But when I really retrieve it remote from the server and test, it seems that I cannot get it display on the list. Can someone help ?
I want to list the title,image and author on the home.html page. Appreciate if anyone can help. Still trying to learn.
I've tried getting other JSON $http.get('https://jsonplaceholder.typicode.com/posts') and it worked. But this particular one is a little difficult for me to understand why it is not parsing correctly. For the code to work, i need to have it on my phone in order to work also. I can see the JSON being downloaded and alerted. But, I don't know why still not seeing the data.
Please see my code as follows.
http://codepen.io/ccrash/pen/VjNPkv
Home.html
<ion-view view-title="Dashboard">
<ion-content class="padding">
<h2>Ionic GET Json Example</h2>
<ion-item ng-repeat="x in result[0].data.items">
<div> {{x.title}} </div>
<div> {{x.image[0]}} </div>
<div> {{x.author}} </div>
</ion-item>
</ion-content>
</ion-view>
Controller
.controller('HomeCtrl', function($http, $scope, $ionicSideMenuDelegate) {
$http.get('http://www.malaysiakini.com/c/en/news?alt=json')
.success(function(data, status, headers,config){
//console.log('data success');
//console.log(data); // for browser console
alert(JSON.stringify(data));
$scope.result = data; // for UI
})
.error(function(data, status, headers,config){
console.log(headers);
console.log('data error');
})
.then(function(result){
things = result.data;
});
})
It's a common issue. I see errors in browser console:
It's usually because you are request to a different domain than your page is on, browser will block your request for security consideration. According to my experience, you can use jsonp as your request data type or add Access-Control-Allow-Origin headers to the server's response.
See this question for more infomation

Angular and JSON syntax getting confused with {}

I am new to angular and trying to integrate it within my application. I am attempting to use a simple ng-repeat (which works perfectly in an example project i setup). However, in the current project, i am using the Swig templating language, which fetches data from a .JSON file using {{ }} e.g:
person.html file:
<div> {{ myFirstName }} </div>
<div> {{ mySurName }} </div>
person.json file:
{
"myFirstName" : "Joe",
"mySurName" : "Bloggs",
}
I think the problem i am facing, is that Swig uses {{ }} to get data from .JSON files, and Angular uses {{ }} too.
Here is my simple ng-repeat:
<ul ng-controller="MyCtrl">
<li ng-repeat="country in countries">
{{country.name}} has population of {{country.population}}
</li>
</ul>
Here is my simple controller:
require(['app'], function(app) {
'use strict';
app.controller("MyCtrl", function($scope) {
$scope.countries = [
{name: 'France', population: 63.1},
{name: 'United Kingdom', population: 61.8}
];
});
});
When opening my HTML page, all that is displayed is:
has population of
has population of
Any ideas of how i can get around this?
Thanks
UPDATE
I would like angular to retrieve the data from the .JSON file
UPDATE Folloiw David Beech's recommendation
Application Tree:
- application
- resources
- CSS
- img
- JS
- data
- countries-data.json
- pages
- countries.html
In the example solution below my $http.get was
$scope.countries = [];
$http.get('/resources/data/countries-data.json', function(data){
Error shown in Firebug: "NetworkError: 404 Not Found - http: // localhost:8000/resources/data/countries-data.json"
To answer part 2 of your question and get angular to retrieve the json file use the $http service. http://docs.angularjs.org/api/ng/service/$http
app.controller("MyCtrl", function($scope, $http) {
$scope.countries = [];
$http.get('/path/to/data.json', function(data){
$scope.countries = data;
}, function(error) {
//handle error here
});
});
And to answer part 1:
I'm not familiar with swig and after a quick google I notice this is available server-side on node or client side and you don't specify how you are using it.
If you are using it server-side I would recommend you check it's documentation about escaping certain bindings to ensure pages are being delivered with the bindings in the html (you can check this by 'view page source' option in chrome).
UPDATE: http://paularmstrong.github.io/swig/docs/api/#SwigOpts
I notice here you can set the varControls binding to something other then '{{' and '}}'.
If you are using it client side then I would ask why you need it at all.. angular works best when you give it as close to complete and exclusive control over the DOM as possible. I'm sure anything that is possible in most templating engines is possible in angular with a little more learning and training and there are plenty of resources for that if you just do a little googling.
Hope this helps.
You can change the start and end interpolation tags using interpolateProvider service.
angular.module('myApp', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
}
);
http://docs.angularjs.org/api/ng.$interpolateProvider