I'm playing with Restangular and I want to make a call to .save() to update or create an entity. From Restangular github page I can see that it is possible to update or create a new account. But if there are no accounts on the server I get method does not exists. (firstAccount is undefined)
Restangular.all('accounts').getList().then(function(accounts) {
var firstAccount = accounts[0];
firstAccount.title = "New title"
// PUT /accounts/123. Save will do POST or PUT accordingly
firstAccount.save();
});
My question is how do I make firstAccount a restangular object that will go to the correct url (POST /accounts) when I call firstAccount.save() if there are no accounts in the response?
If you are trying to create a new element, you may restangularize it:
var account = {
title: 'New Title'
};
var restangularAccount = Restangular.restangularizeElement(null, account, 'accounts');
restangularAccount.save();
That will do an HTTP POST to /accounts
Related
I am follow this tutorial in order to get a transactions/accounts detail from the plaid API. Plaid'd quickstart guide user ejs in order to send to the server with the onSuccess function. How do I create this token using ionic?
Plaid quick guide also suggests that we use code blow
var linkHandler = Plaid.create({
env: 'sandbox',
clientName: 'Client Name',
key: '<PUBLIC_KEY>',
product: ['auth', 'transactions'],
token: '<GENERATED_PUBLIC_TOKEN>',
onSuccess: function(public_token, metadata) {
// You do not need to repeat the /item/public_token/exchange
// process when a user uses Link in update mode.
// The Item's access_token has not changed.
},
and also suggest to use this code
// Create a public_token for use with Plaid Link's update mode
client.createPublicToken(ACCESS_TOKEN, (err, result) => {
// Handle err
// Use the generated public_token to initialize Plaid Link in update
// mode for a user's Item so that they can provide updated credentials
// or MFA information
const publicToken = result.public_token;
});
in order to create a public token and get the access token. I can't use this function because I'm getting an error 'Plaid and/or client is not defined
How do I create this public token using Ionic front end and node back end?
What's the workflow here?
Thanks in advance
On the server side, you'll need to initialize the Plaid node client library first. You will also want to make an exchange token call, to exchange the public_token from Link for an API access_token. You'll then save the access_token and use it to retrieve transaction and account data:
// Initialize the Plaid API client with your API keys (https://dashboard.plaid.com/account/keys)
// Use plaid.environments.production, plaid.environments.development, or plaid.environments.sandbox
const plaid = require('plaid');
const client = new plaid.Client(client_id, secret, public_key, plaid.environments.sandbox);
client.exchangePublicToken(PUBLIC_TOKEN, function(error, tokenResponse) {
if (error != null) {
var msg = 'Could not exchange public_token!';
console.log(msg + '\n' + error);
}
const ACCESS_TOKEN = tokenResponse.access_token;
const ITEM_ID = tokenResponse.item_id;
console.log('Access Token: ' + ACCESS_TOKEN);
console.log('Item ID: ' + ITEM_ID);
// Now retrieve transactions or account information with the access_token
});
For the client-side in your Ionic app, you'll need to include the link-initialize.js script before calling Plaid.create. Specifically:
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js">
</script>
Here's a full client-side HTML example:
<button id="link-button">Link Account</button>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript">
var handler = Plaid.create({
clientName: 'Plaid Walkthrough Demo',
env: 'sandbox',
key: '[PUBLIC_KEY]', // public_key is at https://dashboard.plaid.com/account/keys
product: ['auth'],
onLoad: function() {
// Optional, called when Link loads
},
onSuccess: function(public_token, metadata) {
// Send the public_token to your app server.
// The metadata object contains info about the institution the
// user selected and the account ID, if `selectAccount` is enabled.
$.post('/get_access_token', {
public_token: public_token,
});
},
onExit: function(err, metadata) {
// The user exited the Link flow.
}
});
</script>
An Angular library was recently created: click here and here
I had some issues implementing Plaid successfully at first; these tips should help:
Implement the library as shown in the second link above. Make sure for step two you import in your app.module.ts file. Don't use the jQuery provided in the documentation.
Using this library, a button will be automatically created within the Angular element <mr-ngx-plaid-link-button>. This button will act as a submit button unless you use DOM or other methods to change it to type button on ngAfterViewInit()
All five events in step three are listeners for various events. The onSuccess() callback will return the public token - only after you have (a) successfully submitted bank credentials (user_good / pass_good on Sandbox) and (b) clicked the Continue button to exit the Plaid Link
I have next WEB API:
GET List<EventHistory> '/service/eventhistories'
GET EventHistory '/service/eventhistories/{id}'
DELETE EventHistory '/service/eventhistories/{id}'
PUT EventHistory '/service/eventhistories'
POST EventHistory '/service/eventhistories'
Using angular i want use #resource to get information from server.
angularApp.factory('eventHistoryFactory', function ($resource) {
return $resource('/inner/service/eventhistories/:id',{id:'#id'});
});
But using this declaration i do not have any API to request the page based on some data.
var pageRequest = {
size: size,
page: page
};
or to send update for eventHistory entity.
Based on OP's comment:
Say you want to update a single entity:
.controller('someCtrl', function($stateParams, eventHistoryFactory){
//For the sake of the demonstration - id comes from the state's params.
var eventHistory = eventHistoryFactory.get({id: $stateParams.id});
eventHistory.$promise.then(function(){
//Modify the entity when HTTP GET is complete
eventHistory.address = 'New York';
//Post the entity
eventHistory.$save();
//If you wish to use PUT instead of POST you should declare that
//in the class methods of $resource
});
//Another example using query
var entries = eventHistoryFactory.query({
page: 0,
size: 20,
before: Date.now()
});
//This is translated into GET /inner/service/eventhistories?page=0&size=20&before=111111111111
//and should be interpreted correctly by your backend.
entries.$promise.then(function(){
//entries now contain 20 first event history with date earlier than now.
var specificEntry = entries[0];
//Same deal - modify the entity when HTTP GET is complete
specificEntry.address = 'New York';
//Post the entity
specificEntry.$save();
});
the first answer seems good, but i think this way more understandable and simply for begginers:
eventHistoryFactory.get(pageRequest, function (returnData) {
console.trace('request processed successfully: ' + returnData);
params.total(returnData.totalElements);
$defer.resolve(returnData.content);
}, function (error) {
console.log('request processed with error: ' + error);
})
to make page request in dynamic way the object should be build before request from ngTable current properties (use ngTable API).
Please pay your attention to eventHistoryFactory. It does not have parameter for pageRequest object, but it works -angular magic. By GET request in url you can see:
?page=2&size=25
I'm trying to implement some simple using registration using Firebase through AngularFire and Angular.js. I'm using the SimpleLogin tool to manage the users. I can create users just fine.
var firebaseRef = new Firebase(FIREBASE_URL);
var simpleLogin = $firebaseSimpleLogin(firebaseRef);
var firebaseUsersRef = new Firebase(FIREBASE_URL + 'users');
var firebaseUsers = $firebase(firebaseUsersRef);
var myObject = {
register: function(user) {
var myDate = new Date().getTime();
return simpleLogin.$createUser(
user.email, user.password)
.then(function(regUser) {
var userInfo = {
date: myDate,
md5: regUser.md5_hash,
firstname: user.firstname,
lastname: user.lastname,
email: user.email
}
firebaseUsers.$push(userInfo).then(function(ref) {
userInfo.uid = ref.name();
$rootScope.currentUser = userInfo;
});
}); //push user
}, //register
Works like a charm. In order to get at this information when the user logs in, I've tried implementing an event handler on the $rootscope. I would like it to search through the uid that I stored and then get me record with the right user information.
$rootScope.$on('$firebaseSimpleLogin:login', function (e, authUser) {
var query = $firebase(firebaseRef.startAt(authUser.uid).endAt(authUser.uid));
console.log(query);
$location.path('/meetings');
});
In order to use startAt and endAt, do I have to establish $priority. When I try, I get an error stating that I can't have any special characters. So that never works. I don't really care about how this data stored, I just want to get the index of the data so that I can retrieve the right user.
By using $push you tell Firebase to generate a key for you.
This is great for collections where you normally access all children at the same time. But that is not the case for your user info: you want to access the info for the current user.
So instead of using $push to add your user's info, I would use the uid of the user.
In the regular Firebase JavaScript API this can be accomplish with:
firebaseUsersRef.child(reguser.uid).set(userInfo);
The equivalent in AngularFire probably uses $set, but I don't think you have any need for that in your $createUser callback.
Update
It looks like you're trying to add your info to the existing user node that Firebase creates for you. This is the example from that from the Firebase documentation on storing user data:
myRef.child('users').child(user.uid).set({
displayName: user.displayName,
provider: user.provider,
provider_id: user.id
});
You can see that they do access the user's node using child(user.uid) similar to what I proposed.
Lessons
Two relatively small mistakes here as far as I can see:
when you use push/$push, you let Firebase generate the node name for you. In cases where there already is a globally unique ID (such as the uid of a user), you're often better off using that as the node name.
If you know the name of the node you want to retrieve, you don't need a query. You can simply access the node as ref.child(user.uid).
Thanks to Frank, I was able to figure out the right way to do this. In order to make my own users object searchable, I can use the uid from the simpleLogin object. So my register function works like this:
var firebaseRef = new Firebase(FIREBASE_URL);
var simpleLogin = $firebaseSimpleLogin(firebaseRef);
var myObject = {
register: function(user) {
var myDate = new Date().getTime();
return simpleLogin.$createUser(user.email, user.password)
.then(function(regUser) {
var userInfo = {
date: myDate,
md5: regUser.md5_hash,
firstname: user.firstname,
lastname: user.lastname,
email: user.email
}
firebaseUsers.$set(regUser.uid, userInfo);
}); //add user
}, //register
} //my Object
Using set instead of push, I can store the uid from the registered user into the object and then pass along what I want to add as the second parameter. My database will now have the users organized by uid, which can be accessed via a url.
Then, when users log in, Firebase will throw up a login event along with the authenticated user, which I can catch and use to add the current user to the $rootScope that's accessible throughout my application.
$rootScope.$on('$firebaseSimpleLogin:login', function (e, authUser) {
var ref = new Firebase(FIREBASE_URL + '/users/' + authUser.uid);
var user = $firebase(ref).$asObject();
user.$loaded().then(function() {
$rootScope.currentUser = user;
});
$location.path('/meetings');
});
Thanks for pointing me in the right direction Frank.
I have an app where I use FirebaseSimpleLogin, but since I have additional user data, I store it under [my-firebase].firebaseio.com/users/[username]. The snippet below shows how it's done
var User = {
create: function (authUser, username) {
users[username] = {
md5_hash: authUser.md5_hash,
username: username,
email: authUser.email,
$priority: authUser.uid
};
users.$save(username).then(function () {
setCurrentUser(username);
});
},
...
Since data for each individual user, are keyed based on username I prioritize by uid, so I can later fetch additional user data by uid.
When the firebase login event fires, I have the following handler, that is responsible for querying firebase to get the additionala user data, and store it on $rootScope.currentUser via a method setCurrentUser(username)
Here is my login event handler:
var ref = new Firebase(FIREBASE_URL + '/users');
var users = $firebase(ref);
$rootScope.$on('$firebaseSimpleLogin:login', function (e, authUser) {
var query = $firebase(ref.startAt(authUser.uid).endAt(authUser.uid));
query.$on('loaded', function () {
//PROBLEM: console.log(query.$getIndex()) logs an empty array
setCurrentUser(query.$getIndex()[0]);
});
});
As soon as the login event fires, I get access to the authUser, which contains the uid of the logged in user. Then I query firebase /users by uid, using startAt/endAt to limit my results so that I'm left only with the currently logged in user.
Then, when the query data is loaded from firebase, I invoke the setCurrentUser method which stores the username of the currentUser on $rootScope.
The Problem
The query filtering using startAt/endAt does not work, I'm getting back an empty array when I console.log query.$getIndex() when I should be getting an array with the username of the currently logged-in user.
I'm using firebase 1.0.15, angularFire 0.7.1 and firebase-simple-login 1.4.1 and following this tutorial from Thinkster.io
In the end somewhere in my code I had a $save() on my user binding, to save the id of the last project they've been working on, and this was causing the $priority issue. I used $update instead, and now everything works like a charm!
Still I don't know if this is intended behavior of $save()
To clarify and provide more context, I wasn't passing any keys to the $save() method, I simply added a property on my local user reference, and saved it
$rootScope.currentUser.lastWorkingProject = projectId;
$rootScope.currentUser.$save();
I have a collection of users (model user)
model has a boolean value: isExport
i have a button that on click supposed to post to the server all the users that isExport=true
Can anyone suggest a suitable solution for this problem?
I know it's possible to wrap the collection as a model and overwrite the toJSON function
but couldn't manage it so far (can someone please give a code example?)
App.User = Backbone.Model.extend({ defaults: {isExport: false}...});
App.Users = Backbone.Collections.extend({model: App.User...});
Thanks!
Roy
Backbone collections by default don't have any write operations to the server, so you'll need to add a new method to your Collection subclass such as doExport, use .where to get the models with isExport=true and their toJSON() to get an array of objects which you can then send to the server with Backbone.sync or $.post.
Backbone comes with RESTful support.
So, if you give each collection a url pointing to the collection rest service, then with a few functions (create,save) you can handle server requests.
App.Models.User = Backbone.Model.extend();
App.Collections.Users = Backbone.Collection.extend({
url: 'users',
model: App.Models.User
});
So, this way, you can:
var users = new App.Collections.Users();
users.fetch(); // This will call yoursite.com/users
// Expecting a json request
And then you can:
users.create({ name: 'John', isExport: true });
This will send a post request to the server, in order to create a new record.
And you can check on server side if it has the flag you want.
App.Views.ExportAll = Backbone.View.extend({
el: '#exportAll',
events: {
'click': 'exportAll'
},
exportAll: function(e){
e.preventDefault();
console.log('exporting all');
console.log(this.collection.toJSON());
var exportModel = new App.Models.Export;
exportModel.set("data", this.collection.toJSON());
console.log(exportModel.toJSON());
exportModel.save();
}
});
I think this is the best solution for the problem