I am trying to use http with Angular2.
Here is my code:
var _domain = 'http://localhost:3000/';
app.Applications = ng.core.Injectable().Class({
constructor: [ng.http.Http, function(http) {
this.http = http;
this.emailExistUrl = _domain + 'api/applications/email';
}],
doesEmailExist: function(email) {
var data = { email: email };
return this.http.post(this.emailExistUrl, data)
.toPromise()
.then(function(response) { response.json().data; })
.catch(this.handleError);
}
});
The main component:
app.AppComponent = ng.core
.Component({
selector: 'register-form',
templateUrl: 'src/register/app.component.html',
providers: [app.Applications]
})
.Class({
constructor: [ng.core.ElementRef, app.Applications, function(ref, Applications) {
this.programs = JSON.parse(ref.nativeElement.getAttribute('programs'));
this.applications = Applications;
}],
doesEmailExist: function(email) {
return this.applications.doesEmailExist(email);
}
});
Here is main.js file:
document.addEventListener('DOMContentLoaded', function() {
ng.platformBrowserDynamic.bootstrap(app.AppComponent, [
ng.forms.disableDeprecatedForms(),
ng.forms.provideForms(),
ng.http.HTTP_PROVIDERS,
]);
});
When doesEmailExist is called I get an error from the http module:
vendor-client.min.js:55470 TypeError: Cannot read property 'platform_browser_private' of undefined
Any ideas?
FIXED:
Http was before platform-browser on the script tag list. :/
<script src="https://npmcdn.com/#angular/http/bundles/http.umd.js"></script>
<script src="https://npmcdn.com/#angular/platform-browser/bundles/platform-browser.umd.js"></script>
<script src="https://npmcdn.com/#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>
The inverse is better :)
Try to assign http at the beginning of the constructor:
app.Applications = ng.core.Injectable().Class({
constructor: [ng.http.Http, function(http) {
this.http = http;
...
}],
doesEmailExist: function(email) {
...
}
});
EDIT
See this Plunker: http://plnkr.co/edit/aQWqxauklT7MqSjfhLFD. To simplify, I have put everything in main.js file, and instead of an http post I have implemented an http get. However, locally, even the http post works with a web service API. I hope it's helpful to solve your problem.
Related
I want to create a new document in Firestore using the REST API.
Very good examples here using Axios to send the POST request with some fields:
https://www.jeansnyman.com/posts/google-firestore-rest-api-examples/
axios.post(
"https://firestore.googleapis.com/v1/projects/<PROJECTIDHERE>/databases/(default)/documents/<COLLECTIONNAME>",
{
fields: {
title: { stringValue: this.title },
category: { stringValue: this.category },
post: { stringValue: this.post },
summary: { stringValue: this.description },
published: { booleanValue: this.published },
created: { timestampValue: new Date() },
modified: { timestampValue: new Date() }
}
}
).then(res => { console.log("Post created") })
And an example here using Python Requests:
Using the Firestore REST API to Update a Document Field
(this is a PATCH request but the field formatting is the same as in a POST request)
import requests
import json
endpoint = "https://firestore.googleapis.com/v1/projects/[PROJECT_ID]/databases/(default)/documents/[COLLECTION]/[DOCUMENT_ID]?currentDocument.exists=true&updateMask.fieldPaths=[FIELD_1]"
body = {
"fields" : {
"[FIELD_1]" : {
"stringValue" : "random new value"
}
}
}
data = json.dumps(body)
headers = {"Authorization": "Bearer [AUTH_TOKEN]"}
print(requests.patch(endpoint, data=data, headers=headers).json())
I am using Google Apps Script UrlFetchApp.fetch to send my requests. I am able to use GET requests with no problems. For example, to get all the documents in a collection (in Google Apps Script):
function firestore_get_documents(){
var options = {
headers: { 'Authorization': 'Bearer ' + ScriptApp.getOAuthToken() },
method:'GET'
}
var response = UrlFetchApp.fetch('https://firestore.googleapis.com/v1/projects/<PROJECTIDHERE>/databases/(default)/documents/myCollection', options);
var parsed = JSON.parse(response.getContentText());
return parsed;
}
This works nicely. And changing 'method' to 'POST' creates a new document in myCollection as expected. Then I try to add a POST body with some fields (or just one field):
function firestore_create_new_document(){
var options = {
headers: { 'Authorization': 'Bearer ' + ScriptApp.getOAuthToken() },
method:'POST',
payload: {fields: { title: { stringValue: 'newTitle' } } }, // If you comment out this line, it works as expected
muteHttpExceptions:true
}
var response = UrlFetchApp.fetch('https://firestore.googleapis.com/v1/projects/<PROJECTIDHERE>/databases/(default)/documents/myCollection', options);
var contentText = response.getContentText();
var parsed = JSON.parse(response.getContentText());
return parsed;
}
I get the following errors:
code: 400 message: "Request contains an invalid argument."
status: "INVALID_ARGUMENT"
details[0][#type]: "type.googleapis.com/google.rpc.BadRequest"
details[0][fieldViolations][0][field]: "{title={stringValue=newTitle}}"
details[0][fieldViolations][0][description]: "Error expanding 'fields' parameter. Cannot find matching fields for path '{title={stringValue=newTitle}}'."
Documentation is available here:
https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents/createDocument
https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents#Document
The problem may be the formatting of my 'fields' object - I've tried several different formats from the documentation and examples
The problem may be that the fields don't exist yet? I think I should be able to create a new document with new fields
The problem may be with the way UrlFetchApp.fetch sends my JSON body. I have tried using payload = JSON.stringify(payload_object) and that doesn't work either.
I think UrlFetchApp is doing something slightly different than Axios or Python Requests - the body is getting sent differently, and not parsing as expected.
How about the following modification?
From:
var options = {
headers: { 'Authorization': 'Bearer ' + ScriptApp.getOAuthToken() },
method:'POST',
payload: {fields: { title: { stringValue: 'newTitle' } } }, // If you comment out this line, it works as expected
muteHttpExceptions:true
}
To:
var options = {
headers: { 'Authorization': 'Bearer ' + ScriptApp.getOAuthToken() },
method:'POST',
payload: JSON.stringify({fields: { title: { stringValue: 'newTitle' } } }),
contentType: "application/json",
muteHttpExceptions:true
}
When I tested above modified request, I could confirm that it worked. But if other error occurs, please tell me.
Reference:
Class UrlFetchApp
So I'm using the native HTTP cordova plugin for my http requests. But I can't seem to wrap my head around a problem where I can't create an alert inside the onFail function. Anyone else experienced this?
The error says:
Error in Error callbackId: CordovaHttpPlugin1608257770 : TypeError: Cannot
read property 'alertCtrl' of undefined
Here's how I structured my code:
cordova.plugin.http.sendRequest('http://127.0.0.1:5000/api/login/', options, function(response) {
try { //onSuccess
response.data = JSON.parse(response.data);
localStorage.setItem('token', JSON.stringify(response.data.token));
} catch(e) {
console.error('JSON parsing error');
}
}, function(response) { //onFail
console.log('403');
let alert = this.alerts.create({
title: 'Error',
subTitle: 'Username/password is invalid!',
buttons: ['Dismiss']
});
alert.present();
}
);
Here's how my constructor looks like:
constructor(public navCtrl: NavController,
private alerts: AlertController,
private http: HTTP,
private store: Storage,
) {}
What's causing it to not work?
Try this, because when you create alert in request "this" means httprequest so that hasn't alert class
let alert = this.alerts.create({
title: 'Error',
subTitle: 'Username/password is invalid!',
buttons: ['Dismiss']
});
cordova.plugin.http.sendRequest('http://127.0.0.1:5000/api/login/', options, function(response) {
try { //onSuccess
response.data = JSON.parse(response.data);
localStorage.setItem('token', JSON.stringify(response.data.token));
} catch(e) {
console.error('JSON parsing error');
}
}, function(response) { //onFail
console.log('403');
alert.present();
}
);
Polymer 1.* and Firebase
How can do a async operation where this.$$('#ironAjax').generateRequest(); is call after return '{"Authorization": "Bearer ' + token + '"}';? I have to return the header value and then invoke the iron-ajax request.
<iron-ajax
url="[[HOST]][[LISTINGS]]?foo=foo"
id="ironAjax"
handle-as="json"
headers="[[setAuth()]]",
on-error="errorHandler"
loading="{{ironLoading}}"
last-response="{{listings}}"></iron-ajax>
pageActivated: function(activated) {
if (activated) {
this.setAuth();
}
},
setAuth: ()=> {
firebase.auth()
.onAuthStateChanged((token) => {
return '{"Authorization": "Bearer ' + token + '"}';
this.$$('#ironAjax').generateRequest(); // NEED TO CALL AFTER
// HEADER IS SET
})
I was able to handle the situation with a direct modification to the header. Hopefully this can help anyone else in the same situation:
Behavior:
<script>
AuthIronAjax = {
rawSetAuth: (user, ajax) => {
if (user) {
user.getIdToken().then((token) => {
ajax.headers['Authorization'] = 'Bearer ' + token;
ajax.generateRequest();
});
}
},
setAuth: function (ajax) {
firebase.auth()
.onAuthStateChanged((user)=> this.rawSetAuth(user, ajax));
}
};
</script>
Element it is used in. Note: iron-pages is being used with a implied host property binding activated:
observers: ['pageActivated(activated)'],
behaviors: [AuthIronAjax],
pageActivated: function(activated) {
if (activated) {
this.setAuth(this.$.ironAjax);
}
},
I am working with Angular2 and es5. I want to use http in a service.
Unfortunately I have 2 errors:
- http is undefined, but ng.http.Http is defined,
- I have this error for the main component:
vendor-client.min.js:28 EXCEPTION: Can't resolve all parameters for class0: (t, ?)
Here is my service code:
;(function(app, ng) {
console.log(new ng.http.Http());
app.ApplicationsService = ng.core.Injectable().Class({
constructor: [ng.http.Http, function(http) {
console.log(http);
this.applicationsEmailUrl = 'api/applications/email';
this.http = http;
}],
emailExists: function(email) {
console.log(email);
var data = { email: email };
return this.http.post(this.applicationsEmailUrl, data)
.toPromise()
.then(function(response) { response.json().data; })
.catch(this.handleError);
}
});
})(window.app || (window.app = {}), window.ng);
Here is the main component:
;(function(app, ng) {
app.AppComponent = ng.core
.Component({
selector: 'register-form',
templateUrl: 'src/register/app.component.html'
})
.Class({
constructor: [ng.core.ElementRef, app.ApplicationsService, function(ref, Applications) {
console.log('app.component.js');
this.programs = JSON.parse(ref.nativeElement.getAttribute('programs'));
this.applications = Applications;
}],
emailExists: function(email) {
console.log('emailExists() triggered');
Applications.emailExists(email);
}
});
})(window.app || (window.app = {}), window.ng);
The bootstrap:
;(function(app, ng) {
document.addEventListener('DOMContentLoaded', function() {
ng.platformBrowserDynamic.bootstrap(app.AppComponent, [
ng.forms.disableDeprecatedForms(),
ng.forms.provideForms(),
ng.http.HTTP_PROVIDERS,
app.ApplicationsService
]);
});
})(window.app || (window.app = {}), window.ng);
If I try to inject http into the main component within the providers array, it works. But I would rather prefer to have a service.
I found out the problem. Looks like Angular2 needs to load your code in order. The main component was loaded before the service, so it was undefined. I put all my code in one file and it works. I will use a require loader asap.
Is there anything wrong with this code where I am trying to have one service method point to different restful services?
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function ($resource) {
return {
pList: $resource('/:url/:phoneId.json.htm', {}, {
query: { method: 'GET', params: { url: 'MyAngularScripts', phoneId: 'jsonPhonedata' }, isArray: true }
}),
pDetail: $resource('/Content/PhonesData/:phoneId.json.htm', {}, {
query: { method: 'GET', params: { phoneId: $routeParams.phoneId }, isArray: false }
})
};
}]);
Then in my controller I call the pList like this:
$scope.phones = Phone.pList.query();
The service method doesnt get called with any of the code above. However if I change the service to this:
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function ($resource) {
return $resource('/:url/:phoneId.json.htm', {}, {
query: { method: 'GET', params: { url: 'MyAngularScripts', phoneId: 'jsonPhonedata' }, isArray: true }
});
}]);
and call from the controller like this:
$scope.phones = Phone.query();
IT works. What is wrong with the service where I have multiple restful calls declared? SOmething wrong with the way its configured or the way I am calling it?
The 1st approach should be working fine as well.
The only oroblem is that you are trying to access a property of $routeParams, without first injecting it via DI, thus resulting in an Error being thrown.
If you correct this, everything should work as expected.