How to change data without reloading page with Angular and Node JS - javascript

Client data:
accounts = [
Account1 = {
name: 'Dan', phone: 1775123, role: 'Client', email: 'none'
},
Account2 = {
name: 'Messy', phone: 3564576, role: 'Client', email: 'none'
},
Account3 = {
name: 'Sasha', phone: 34231234, role: 'Client', email: 'Sania#mail.ta'
}
];
DOM:
<div ng-repeat="account in accounts" >
<table>
<tr>
<td><input type="checkbox" ng-change="Toggle(account.name)"/>{{ account.name }}</td>
</tr>
</table>
</div>
I just want to figure out what's the best way to change array data in DOM without page reloading. For instance I got some data in view using ng-repeat directive. I selected the option I needed and sent it to NodeJS -> MongoDB. Now I want to get this data in the same place without reloading my page.
It sounds like a very typical question, but I've been trying to find a solution for quite long time.

Just update the data in your controller and angular will update the dom. This is a small example of 2 way data binding which I think is what you want:
Plunker example
In the Toggle method you will put in your service that hits the db and changes the data:
$scope.Toggle = function(idx, account){
$scope.accounts[idx].name = account.name + " Edited";
//replace above with whatever updates the account, ie, businessService.updateAccount(account);
}

I'm assuming that you posted the data to the server and db using a post request (i.e. $http.post(url, data)).
In Angular, all Ajax calls have a a promise to the success method, therefore in the success method, do a get request to the server to retrieve your data i.e.:
$http.post(url, data)
.success(function(){
$http.get(url)
.success(function(data){
updateAccounts(data) // a function to update your accounts array
}
})
On the Server side, your node server should be listening for a get request to the above get url, and then it should use the callback to query the database for the accounts:
app.get(url, function(req, res){
// Query the database for accounts and send back result of query
res.send(200, accounts);
})
Hope that helps!

Related

Waterline relations in SailsJS

I write an application in SailsJS and i have a problem with relations,
some code at the beginning:
User.js
module.exports = {
tableName: 'user',
attributes: {
schedules: { collection: 'userworkstationschedule', via: 'user' },
}
UserWorkstationSchedule.js
module.exports = {
tableName: 'user_workstation_schedule',
attributes: {
user: { model: 'user', required: true },
}
}
After run my code in Postaman, in JSON response i get:
{
...
"user": 2,
...
}
I get only ID of my user, but i want to get a whole object of User model with his firstname, lastname, etc.
Ccould anyone help me?
I'm more accustomed to a sails 0.12, but I know there you can configure your app so that population happens automatically, but it is not the default - to do this, go into config/blueprints.js and set the populate option to true.
However, I recommend against this - population may not be something you need on every page / every api call. You can make your api calls with population requests built in, like so:
/api/userworkstationschedule/[workstationid]?populate=user
That should make the populate happen just for that api call.

Javascript, Redux thunk, synchronous / nested promises

I have a direct messaging application. All the data is stored in Firebase. Each chat contains an array of user IDs.
I use the following function to get all chats from componentDidMount():
return dispatch => new Promise(resolve => FirebaseRef.child('chats')
.on('value', snapshot => resolve(dispatch({
type: 'CHATS_REPLACE',
data: snapshot.val() || [],
})))).catch(e => console.log(e));
Which goes through:
chatReducer(state = initialState, action) {
case 'CHATS_REPLACE': {
let chats = [];
if (action.data && typeof action.data === 'object') {
chats = Object.values(action.data).map(item => ({
id: item.id,
title: item.title,
authorizedUsers: Object.values(item.authorizedUsers).map(user => ({
id: user.id,
// Somedata: fetchUserData(user.id)
// -> pretty sure it can't be done here <-
})),
}));
}
return {
...state,
error: null,
loading: false,
chats,
};
How would I go about fetching more data of every user inside each chat from Firebase at users/:uid?
I don't know what is the use case of this. It would be great if you can share, like how much information about the user you want to use. If its small data, why don't you add it in same API Only. You can pass the users data in the same object with user id as keys, and use the same keys inside your nested data like (only if user data is small or you know API data is always limited like because of pagination or page size. :
{
posts : [
{
title : 'abc'
authorizedUsers : ['1a', '2b', '3c']
}, ....
],
users : {
'1a' : {
name : 'john doe',
profileImage : 'https://some.sample.link',
},
'2b' : {
name : 'bob marshal',
profileImage : 'https://some.sample.link2',
}
}
}
If data is huge or cannot be added in the API ( because API is owned by 3rd party), then only place you can put you code is, instead of just dispatching the actions after the response is recieved, loop over the response in your service only, make async calls to get all "Unique users" only, append that data to the data you recieved from the previous api call, and then dispatch the action with the complete data to the store. It might not be the best way, as everything will have to stall i.e. even the data recieved in 1st api also will stall(not updated on screen) till all the users data is fetched. But best solution can only be given once we know more details about the use case. Like maybe lazy fetching the users data as end user scrolls the screen and may see a particular post Or fetching the user details once you start rendering your data from 1st API call like making a component for showing user associate with a post and in its componentDidMount, you pass the userIds as props from top component which might be "article/post/blog" component and it fetched the data at the time when it is actually rendering that "article/blog/post".
Hope this helps.

Is there a way to save multiple embedded models in db at once using Sequelize

Suppose we have a such structure in NodeJs Sequelize.
var User = sequelize.define('user', {/* ... */})
var Project = sequelize.define('project', {/* ... */})
Project.hasMany(User)
In this part of video presenter offers to save embedded objects with two steps using promises. In our case it would be something like:
Project.create({
...
}).then(function(project){
User.create({
...
projectId:project.id
})
})
But this approach will result two db calls.
So, is it possible to save embedded objects (Project which contains User e.g. User must have Project's id as a foreign key) into the db with one db call or within a transaction using Sequelize?
You should be able to insert parent-children by passing an array of objects into a key with the same name as the "as" value used on the "include". Although the documentation is light on the usage, you can see it handled in the source code here.
No promises (pun semi-intended) that this is actually run in single SQL query, not sure of the exact implementation in Sequelize. You should be able to enable logging (logging: console.log in the Sequelize(options)) to see what it's running.
// specify an "as" value and require a User.project_id value
Project.hasMany(User, { as: 'Users', foreignKey: { allowNull: false } });
// define your Project -> Users as json with the "as" value as the key
const project = {
name: 'project name',
Users: [
{
name: 'user 1',
},
{
name: 'user 2',
},
],
};
// create a transaction and "include" the Model in the create, txn falls back in .catch()
sequelize.transaction(t =>
Project.create(project, {
include: [{
model: User,
as: 'Users',
}],
transaction: t,
})
)
.catch(e => console.log('the txn failed because', e));

MongoDB _id as a String (MEAN Stack)

TL;DR - I am trying to use a collected value from a form input as a document _id but am getting a 404.
I've got a modal that opens and collects form data. My first input in the form is:
<input type="text" id="name" name="name" data-ng-model="name" />
When I try to modify the Mongo (Mongoose) model, to use name as the _id, the form wont post. I get a 404 from http://sitegoeshere/#!/somethings/whatever_i_type_in_for_name
Example model:
var SomethingSchema = new Schema({
_id: {
type: String,
default: 'default',
trim: true
}
}
mongoose.model('Something', SomethingSchema);
And in my Angular controller:
$scope.create = function() {
// Create new Something object
var something = new Somethings ({
_id: this.name
});
// Redirect after save
something.$save(function(response) {
$location.path('somethings/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
I've been told that MongoDB allows Strings as the _id type so what gives? Any ideas?
UPDATE: Here's something strange, too. I wanted to see if maybe this was a limitation or bug of Mongoose so I got into the database and created two documents:
> db.subnets.find().pretty()
{ "_id" : ObjectId("546bef63395b0694d51b5cbe"), "description" : "description!" }
{ "_id" : "mystring", "description" : "more description!" }
When I go to my app and try to pull their individual views up, I can see the data for my custom _id document but get a 500 Internal Server Error when I try to access the other.
GET http://localhost:3000/somethings/546bef63395b0694d51b5cbe 500 (Internal Server Error)
GET http://localhost:3000/somethings/mystring 200 OK
The problem is most likely with this.name - looks like it's undefined.

Sending 2 objects in 1 POST request

I'm using Angular and trying to send a request (using $resource) to an external API but I have the data I need to send in 2 different objects, while I currently only send 1. The API requires user specific actions to include an auth_token with every request.
Without the auth_token, the request would look like this:
APIShop.reg(Cart.data,
function(success) {},
function(failure) {}
);
APIShop looks like this:
app.provider('APIShop', function(API_URL) {
this.$get = ['$resource', function($resource) {
var Campaign = $resource(API_URL.url + API_URL.loc + ':service/:action/', {service: '#service', action: '#action'}, {
'reg': {method:'POST', isArray: false, params: {service: 'account', action: 'order'}},
'update': {method:'PUT', isArray: false, params: {service: 'account', action: 'order'}}
});
return Campaign;
}];
});
Cart.data is an object that looks like: {country: 'US', city: 'Seattle, WA'}
but I need to also add {auth_token: '432078e36c7a42e3c6febdac95f38c1549de6218'} from the User object in the same request. The immediate solution would probably be to add the auth_token field to the Cart object, but as I'm storing this data in the application in various models User, ShoppingCart, etc, I'd like to keep auth_token in the User object.
I tried doing
APIShop.reg(Cart.data, User.auth_token
function(success) {},
function(failure) {}
);
didn't expect it to work, and it didn't. The auth_token ends up showing as a Request Payload instead of Query String Parameters.
I also don't want to send something like {country: Cart.data.country, city: Cart.data.city, auth_token: '432078e36c7a42e3c6febdac95f38c1549de6218'} directly (as opposed to sending the object) as that will become a maintenance nightmare sooner or later.
How would I go about sending both pieces of information without adding the token to Cart (since it'll mean I need to add it to every object going forward), or listing all the fields of the object?
Refactor APIShop to receive an array:
APIShop.reg([Cart.data, User.auth_token],
function(success) {},
function(failure) {}
);
Or refactor it to receive a mapping object:
APIShop.reg({ data : Cart.data, auth : User.auth_token },
function(success) {},
function(failure) {}
);

Categories