AngularJS - How to create a backend? - javascript

I have an angularjs app on one html page and it pretty much works well. But instead of using constants on a angularjs script, I'd like to make it dynamic where someone can change the values from another page. Here's some sample code I'd like to be dynamic:
// compute base_cost
$scope.base_cost = function(pages, delivery) {
// change this if you want to change price per page
price_per_page = 150;
// change this if you want to change the cost of a 3 day delivery
three_business_days = 100;
base_cost = pages * price_per_page;
if (delivery === "3 Business Days"){
base_cost = pages * price_per_page + three_business_days;
}
return base_cost;
};
I'd like the price_per_page and three_business_days to have a seperate page (maybe password-protected) where these variables' constants can be changed by the client when he wants to change the price, etc.
What is the simplest way to do this?
P.S. I'm already currently searching about it, but just a bit of guidance would be greatly appreciated.
Thanks

Assuming another page means another view, see this answer. Basically, create a service.

Assuming you want to persist these values across sessions you need more than just a service: you need some kind of API / database.
There are endless choices: node.js, ASP.NET Web API, etc. Depends on your experience.
Have you considered firebase to get something up and running quickly (assuming you don't have existing infrastructure to rely on)? There's a reasonable free tier for experimentation.
https://www.firebase.com
There's also some nice AngularJS support:
https://www.firebase.com/docs/web/libraries/angular/index.html
The real time aspect may be overkill though..

What you are describing is a factory / service. It is the model in an MVC application.
In angular, a factory is a singleton, you don't instantiate new copies of it, and changes made to it in one area persist through to another area of site. Of course, that is only during the life of your session, you'd need to store the models state to some other form of storage.
Here is an example application, it has a controller (to show how to use it), and a factory.
angular.module('testModule', [])
.factory('BaseCost', function(){
// change this if you want to change price per page
price_per_page = 150;
// change this if you want to change the cost of a 3 day delivery
three_business_days = 100;
return {
price: function(amt){
price_per_page = amt;
},
days: function(cost){
three_business_dates = cost;
},
base: function(pages){
return pages * price_per_page;
}
};
})
.controller('ACtrl',function($scope, BaseCost){
$scope.setPrice = function(amt){
BaseCost.price(amt);
};
$scope.daysCost = function(cost){
BaseCost.days(cost);
}
$scope.baseCost = BaseCost.base(pages);
});

Related

JS: Node.js and Socket.io - globals and architecture

Dear all,
Im working with JS for some weeks and now I need a bit of clarification. I have read a lot of sources and a lot of Q&A also in here and this is what I learned so far.
Everything below is in connection with Node.js and Socket.io
Use of globals in Node.js "can" be done, but is not best practice, terms: DONT DO IT!
With Sockets, everything is treated per socket call, meaning there is hardly a memory of previous call. Call gets in, and gets served, so no "kept" variables.
Ok I build up some chat example, multiple users - all get served with broadcast but no private messages for example.
Fairly simple and fairly ok. But now I am stuck in my mind and cant wrap my head around.
Lets say:
I need to act on the request
Like a request: "To all users whose name is BRIAN"
In my head I imagined:
1.
Custom object USER - defined globally on Node.js
function User(socket) {
this.Name;
this.socket = socket; }
2.
Than hold an ARRAY of these globally
users = [];
and on newConnection, create a new User, pass on its socket and store in the array for further action with
users.push(new User(socket));
3.
And on a Socket.io request that wants to contact all BRIANs do something like
for (var i = 0; i < users.length; i++) {
if(user[i].Name == "BRIAN") {
// Emit to user[i].socket
}}
But after trying and erroring, debugging, googling and reading apparently this is NOT how something like this should be done and somehow I cant find the right way to do it, or at least see / understand it. can you please help me, point me into a good direction or propose a best practice here? That would be awesome :-)
Note:
I dont want to store the data in a DB (that is next step) I want to work on the fly.
Thank you very much for your inputs
Oliver
first of all, please don't put users in a global variable, better put it in a module and require it elsewhere whenever needed. you can do it like this:
users.js
var users = {
_list : {}
};
users.create = function(data){
this._list[data.id] = data;
}
users.get = function(user_id){
return this._list[user_id];
};
users.getAll = function(){
return this._list;
};
module.exports = users;
and somewhere where in your implementation
var users = require('users');
For your problem where you want to send to all users with name "BRIAN",
i can see that you can do this good in 2 ways.
First.
When user is connected to socketio server, let the user join a socketio room using his/her name.
so it will look like this:
var custom_namespace = io.of('/custom_namespace');
custom_namespace.on('connection', function(client_socket){
//assuming here is where you send data from frontend to server
client_socket.on('user_data', function(data){
//assuming you have sent a valid object with a parameter "name", let the client socket join the room
if(data != undefined){
client_socket.join(data.name); //here is the trick
}
});
});
now, if you want to send to all people with name "BRIAN", you can achieve it by doing this
io.of('/custom_namespace').broadcast.to('BRIAN').emit('some_event',some_data);
Second.
By saving the data on the module users and filter it using lodash library
sample code
var _lodash = require('lodash');
var Users = require('users');
var all_users = Users.getAll();
var socket_ids = [];
var users_with_name_brian = _lodash.filter(all_users, { name : "BRIAN" });
users_with_name_brian.forEach(function(user){
socket_ids.push(user.name);
});
now instead of emitting it one by one per iteration, you can do it like this in socketio
io.of('/custom_namespace').broadcast.to(socket_ids).emit('some_event',some_data);
Here is the link for lodash documentation
I hope this helps.

Custom Tab in the Field Service Schedule Board

I found this blog: http://www.powerobjects.com/2016/08/01/advanced-customizations-for-the-custom-tab-in-the-field-service-schedule-board/#collapse2
In it the author describes using configuration to create a new tab in the Field Services Schedule Board by pointing it to a CRM web resource.
The blog includes the following javascript:
function updateBooking()
{
var entityRecordGuid = "10B8A40B-D499-E611-80E6-A45D36FC5A4C";
// GUID is hardcoded to make the sample code easier to understand.
// We can extend this customization to be able to extract the selected booking IDs
// from the SChedule Board's DOM, but that is out of scope for now
var bookableResourceBooking = new XrmServiceToolkit.Soap.BusinessEntity("bookableresourcebooking", entityRecordGuid);
bookableResourceBooking.attributes["cus_urgency"] = document.getElementById('UrgencyInput').value;
bookableResourceBooking.attributes["cus_notes"] = document.getElementById('NoteInput').value;
var updateResponse = XrmServiceToolkit.Soap.Update(bookableResourceBooking);
if (updateResponse == "") { // clear fields if synced to crm
document.getElementById('UrgencyInput').value = "";
document.getElementById('NoteInput').value = "";
} else {
alert('Data didn't sync to CRM');
}
}
The problem that I've got is that I'm not sure how to get the entityRecordGuid value dynamically.
There doesn't seem to be a way of configuring the web resource to
have the selected Item as part of the querystring
There seem to be undocumented JavaScript libraries for Field
Services; however, I can't access them from the web resource IFrame
and of course, they're undocumented.
Has anyone else tried to do this? I'm using CRM Online
I ended up doing this by scraping the HTML directly rather than trying to use any of the API methods from Field One.
This wasn't really a satisfactory answer for me. It depends on the Unscheduled Orders board being in a certain order and since this is changeable by the end-user my solution is very fragile.
For anyone else looking, I did manage to find these API methods; however, I couldn't find any documentation for them so assume that they are unsupported. I also couldn't tie them together to achieve what I wanted
// get the id of the sub grid
F1SDK.SchedulerPage.UnscheduledOrdersGrid.id
// -> "UnscheduledGrid"
F1SDK.SchedulerPage.UnscheduledOrdersGrid.getItemId()
// -> "UnscheduledGrid"
F1SDK.SchedulerPage.UnscheduledOrdersGrid.getStore().storeId
// -> "UnscheduledWorkOrders"
F1SDK.SchedulerPage.UnscheduledOrdersGrid.getStore().data.items[0].internalId
F1SDK.SchedulerPage.UnscheduledOrdersGrid.selModel.selected.items[0].internalId
// Get a subgrid
FieldOneSkyUtils.Subgrid.GetSubgrid('id')
F1SDK.data.models.WorkOrder.getFields()
F1SDK.data.models.WorkOrder.getIdByWONumber('00106')
// -> {55caa97d-429a-e611-80e6-c4346bc4bef0}

Suggestions on how to deal with this model constantly being re-initialized in a set interval?

I have been recently assigned to maintain EmberJS code at work and I am complete newbie with EmberJS or Javascript, Hence, I came here for help.
Context
I have a live feed page (like a news feed) that is integrated with Infinity Loading and this feed constantly checks with the backend to see for any new messages. This is causing this code to be constantly invoked.
import InfinityRoute from "ember-infinity/mixins/route";
export default Ember.Route.extend(InfinityRoute,{
perPageParam: "perPage",
totalPagesParam: "meta.totalPages",
queryParams: { dateFrom:.... },
model(params){
const defaultParams = { perPage: 25, startingPage: 1 } ;
const modelParams = Ember.$.extend(defaultParams, params);
return this.infinityModel("message", modelParams);
}
The above code will load 25 pages with startingPage as 1 and pass it to the infinityModel which will contact the data store to get the necessary information.
Question Scenario
Above code is constantly bringing you back to page 1 and lose track of the current page
(Example, If you scroll above 25 messages and are in the 2nd page, then the 2nd page keeps disappearing and re-appearing because of the scroll position and model re-initialization setting the startingPage back to 1)
I would love if you guys can provide me with any suggestions on how to handle this model re-initialization and infinityScroll issue?
I'm not sure if I understand your problem correctly but likely we had to solve similar problem. Our backend periodically rewrites model that is used to generate recursive components. These components have some state information that was loose after each model reload. We had decided to solve this using Ember.ArrayProxy.
You want to record 'live-array' where changes will be sent to templates, like when you are using store.findAll() - on other side store.peekAll() returns standard array.

How do I publish a piece of data and then stop reacting to it?

I want to make a homepage where several pieces of data are published, but only when the user first visits the page : one would get the latest 10 articles published but that's it - it won't keep changing.
Is there a way to make the inbuilt pub/sub mechanism turn itself off after a set amount of time or number of records, or another mechanism?
Right now I'm using a very simple setup that doesn't "turn off":
latestNews = new Mongo.Collection('latestNews');
if (Meteor.isClient) {
Meteor.subscribe("latestNews");
}
if (Meteor.isServer) {
Meteor.publish('latestNews', function() {
return latestNews.find({}, {sort: { createdAt: -1 }, limit : 10});
});
}
The pub/sub pattern as it is implemented in Meteor is all about reactive data updates. In your case that would mean if the author or last update date of an article changes then users would see this change immediately reflected on their home page.
However you want to send data once and not update it ever again.
Meteor has a built-in functionality to handle this scenario : Methods. A method is a way for the client to tell the server to execute computations and/or send pure non-reactive data.
//Server code
var lastTenArticlesOptions = {
sort : {
createdAt : -1
},
limit : 10
}
Meteor.methods({
'retrieve last ten articles' : function() {
return latestNews.find({}, lastTenArticlesOptions).fetch()
}
})
Note that contrary to publications we do not send a Mongo.Cursor! Cursors are used in publications as a handy (aka magic) way to tell the server which data to send.
Here, we are sending the data the data directly by fetching the cursor to get an array of articles which will then be EJSON.stringifyied automatically and sent to the client.
If you need to send reactive data to the client and at a later point in time to stop pushing updates, then your best bet is relying on a pub/sub temporarily, and then to manually stop the publication (server-side) or the subscription (client-side) :
Meteor.publish('last ten articles', function() {
return latestNews.find({}, lastTenArticlesOptions)
})
var subscription = Meteor.subscribe('last ten articles')
//Later...
subscription.stop()
On the server-side you would store the publication handle (this) and then manipulate it.
Stopping a subscription or publication does not destroy the documents already sent (the user won't see the last ten articles suddenly disappear).

Load more comments with PHP and AngularJS

I have a table of comments and a table of replies to comments and currently use AngularJS. I have a page for a user and load all the associated comments and replies on his/her profile. Since I'm just testing this on my local server for now, the sample size is very small (less than 10 rows returned). However, in order to create a scalable site, I'm wondering what I can do in terms of buttons or functions like "Load more comments" and "Load more replies".
Do I need to load all the comments of a user ALWAYS? What if the user has 3000 or even 10000 comments on his/her profile and there are more than 10000 users? Won't this take a long time for the profile page to even load? It seems like a waste to load all the comments and replies when less than 1/5 of them will even be seen in the first place. Is there anyway I can query the database to load the first 100 rows, than load the next 100 rows or something similar? What is the formal practice (and optimized for performance for this?)
As well, my general idea for "loading more comments" in Angular if I do always have to load all the comments is something like this:
$scope.allcomments = [some array of comments];
$scope.display = $scope.allcomments.slice(0, 5);
$scope.num = 5;
$scope.loadmore = function() {
var x = $scope.num
$scope.num += 5;
$scope.display.push($scope.allcomments.slice(x, $scope.num));
}
But is there no better way to do it?
I assume you're going to use ngRepeat to show the results, if so:
In view, i.e.:
<div ng-repeat="comment in allcomments | limitTo:num">{{comment}}</div>
In Controller:
$scope.loadmore = function() {
$scope.num += 5;
}

Categories

Resources