Hardcoded Web API calls in code versus multiple environments - javascript

Actually, I hardcode my Web API calls like this :
$http.get('my/production/web/api/method');
If I want to switch to a test environment, which is another Web API, I don't want to manually change every hardcoded call in the code.
Is there a way to solve this by using a configuration file or has angularjs a feature to handle that ?

Like domakas said, use your own config file:
var config={
environment:'production'
//environment:'dev'
};
$http.get('my/'+config.environment+'/web/api/method');
Make your own function:
function queryWebApi(method) {
$http.get('my/'+config.environment+'/web/api/'+method);
}

Related

Using methods for the menu item callbacks in Google Apps Script

So, I am doing a small project in Google Apps Script, to make adding/exporting leads from it...less painful.
How do I plan to do this?
I plan on doing this via adding some Actions menu, for the importing and exporting of leads. The imported sheet will, for now, be assumed to be of the same columns as the Google Sheet this script is bound to. (We can support some sheet column conversion features later, but it's probably a YAGNI for my use case.) The exported sheet will be converted from the columns of this sheet, to some simplified, ready-to-send-to-the-mailers columns.
How do I plan to code this (or how am I coding this)?
I am using MVVM design pattern, and have spent last night plugging away at writing MVVM wrappers for everything that I need to (keeping KISS in mind).
The MenuItemViewModels have some name,functionName that the Google Apps Script seem to be looking for. I note that there is some major pain-in-the-ass limitation, though: Google Apps Script wants function NAME and it cannot be method!
OK, show me some code or gtfo
I have some SpreadsheetPageViewModel that look like this:
class SpreadsheetPageViewModel extends BaseViewModel {
init() {
this.exportVM = new ExportSpreadsheetEditViewModel();
this.importVM = new ImportSpreadsheetEditViewModel();
this.menuVM = new MenuViewModel(new MenuModel(),
[
'exportLeads', // this is utility function. I want/need to use openExport method
'importLeads', // this is utility function. I want/need to use openImport method
]);
this.childEditVM = null;
}
openExport() {
this.childEditVM = this.exportVM;
this.childEditVM.view.doShow();
}
openImport() {
this.childEditVM = this.importVM;
this.childEditVM.view.doShow();
}
}
The business logic for the modals that spawn on menu item click, will live in the child view models to this: the ExportSpreadsheetEditViewModel and ImportSpreadsheetEditViewModel.
I was trying to get around the limitation via this hack:
changing
function onOpen(event) {
// show the menu here....
new SpreadsheetPageView().doShow();
}
to something like:
var mainView;
function onOpen(event) {
mainView = new SpreadsheetPageView();
// show the menu here....
mainView.doShow();
}
and then, in the MenuActionUtils.gs, crawling down that mainView like:
function exportLeads() {
mainView.viewModel.showExport();
}
function importLeads() {
mainView.viewModel.showImport();
}
What was the result of that hack?
It didn't work. Why? Because when Google Apps Script fired that exportLeads (or importLeads), mainView was no longer defined!!
Does this mean I have to give up my approach?
How can I use the main view/view model in the onClick of the menu items?
Failing all that, is there a way to create our menu, using this MVVM design pattern (and some HTML/React/....), and inject it in?
By using Google Apps Script it's not possible to modify the look and feel of a Google Workspace editor (Docs, Forms, Sheets, Slides) custom menu, in other words, it's not possible to use HTML/React for this but you might use them in dialogs/sidebars.
Regarding using a design pattern, you might use any design pattern that you want but you should have in mind that every time that a Google Apps Script is triggered by an event the whole project is loaded, so if you need that some objects persist between events then you should find a place to save those objects.
To store an object you might use the Google Apps Script Properties Service and/or the Cache Service, just bear in mind that you should convert it to JSON before saving it. Also you might use a Google spreadsheet but this has several limitations or you might use an external service, i.e. nosql database, by using Google Apps Script URL Fetch service.
Related
using and modifying global variables within handler functions
Styling a custom spreadsheet menu item using Google Apps Script
How to define global variable in Google Apps Script
Google Apps Script (V8); why can't I use an object instance inside of onOpen?
With #Ruben's help, I was able to get this working!
What I did
I didn't give up on the MVVM/OOP design.
Instead, I created singleton static method on the drive class, like so:
static GetMainInstance() {
if (!this._mainInstance) {
this._mainInstance = new this();
}
return this._mainInstance;
}
and use it instead of directly creating the new drive object.
Also, it is view's responsibility to spawn stuff, so I did some refactoring:
In PageView.gs I added the following methods:
showExport() {
this.viewModel.showExport((childVM) => {
this.editView.viewModel = childVM;
this.editView.doShow();
})
}
showImport() {
this.viewModel.showImport((childVM) => {
this.editView.viewModel = childVM;
this.editView.doShow();
})
}
in the PageViewModel.gs, I changed the methods to accept onDone callback:
showExport(onDone) {
this.childEditVM = this.exportVM;
onDone(this.childEditVM);
}
showImport(onDone) {
this.childEditVM = this.importVM;
onDone(this.childEditVM);
}
Simple fix, it works, while staying consistent with the principles!

How to put external js API in cocos creator?

I am just wondering how to put another js API library( in my case, i want to put the smartfoxserver javascript API library) in cocos creator? because what i did in cocos2d-js, i just need to add it in project.json, and I am wondering if i can do same way in cocos creator or another way?
thank you in advance
reference question from:
http://discuss.cocos2d-x.org/t/how-to-put-another-js-api-library-in-cocos-creator/32598
good day
you can use module exports
var x = {
/*
your stuff
*/
};
module.exports = x;
then access it from other scripts using
var externalScript=require("name of the script with module.exports");
cheers
i just scan the smartfoxserver. it use the websocket that is fine just drag an drop the SFS2X_API_JS.js to the project and require it and init it maybe you would use window.xxx to set the connection handler as global value

How to inject an entire module dynamically in AngularJS?

Alright, so I'm trying to set-up $httpBackend to use as a mock server for local development against an API. I have two services in separate modules: search and searchMock:
search returns a $resource object that exposes the API verbs when in staging or production environments, and works as expected
searchMock exposes $httpBackend which, in turn, responds with mock JSON objects, and works as expected by itself
I have another service, APIInjector, that determines what the current environment is based on a config file that's included dynamically by Grunt when the app is built and injects either search or searchMock accordingly.
My problem is, as far as I can tell from searching high and low, $httpBackend needs to be set-up within a module's run method. The problem with this is I can't inject the run method within my APIInjector's conditional logic.
How can I expose $httpBackend if the dev environment condition is met, and my $resource service otherwise? Note that I didn't include the calling controller's or the searchService's code, but I can if needed for clarification.
searchMock:
var searchMockService = angular.module('searchMockService', []);
searchMockService.run([
'$httpBackend',
function($httpBackend) {
results = [{name: 'John'}, {name: 'Jane'}];
$httpBackend.whenGET('/search').respond(results);
}]);
APIInjector:
var APIInjectorService = angular.module('APIInjectorService', [
'searchService',
'searchMockService'
]);
APIInjectorService.factory('APIInjector', [
'$injector',
'ENV_CONF',
function($injector, ENV_CONF) {
var isDevelopment = ENV_CONF.IS_DEVELOPMENT;
// Check to see if we're in dev and, if so, inject the local API services
if (isDevelopment) {
return {
Search: // Not sure what to do here to expose searchMock's run method???
};
} else {
return {
Search: $injector.get('Search') // This returns $resource from the search service, as expected
};
}
}]);
Just to put a final point on this question, I ultimately pulled this out to my build script (Grunt) and abandoned the above approach completely. Instead, I'm passing in the environment I want to build for (development, staging, production, etc) as a flag to Grunt and then loading the appropriate API service during the build.
Hope that helps someone else trying to implement backendless development!
As bad as it looks at first place, i'd use the document.write method,if you are not using requirejs(it shouldnt be a problem with requirejs).
1 - bootstrap your ENV_CONF variable in a script tag as first script in HEAD tag.
2 - load all the common scripts
3 - test the ENV_CONF.IS_DEVELOPMENT in another SCRIPT tag.
4 - if true document.write('<script src="angular-mocks.js"></script><script src="main-dev-module.js"></script>')
5 - if false document.write('<script src="main-prod-module.js"></script>')
6 - profit
That way you dont need to deal with ENV_CONF.IS_DEVELOPMENT inside your modules.
html5 boilerplate uses this technique to either fetch jquery from a cdn or locally
https://github.com/h5bp/html5-boilerplate/blob/master/index.html
Edit: I'm sure there are cleaner ways to inject services dynamically in angularjs,but that's what i'd do.I'd like someone to propose a better alternative.

How to inject variables to Javascript based on environment?

I'm building a javascript application and basically I have three different environments. Local, CI and QA environments. My back-end service is always going to be deployed separately to my front-end application. So, most of the Ajax calls are going to be CORS. We solved this problem already. However, in my code there's something like this.
jQuery.ajax({"url":"http://www.somecompany.com/api"});
So the problem is going to be in CI and QA environments which ajax calls will hit http://ci.somecompany.com/api and http://qa.somecompany.com/api or even http://test.somecompany.com/api. How do I inject those variables based on the environment I'm running. If it's Java or .NET I could use YAML and everything would be ok. But as Javascript it's client-side how do we choose which url to hit based on environments without find and replace in the code or some hacky way. What do people do to overcome this kind of problem generally?
Just a side note, I'm using Knockout.js
If you build your application with grunt then use grunt-variablize. Put your configuration into resources/config.json
{
"test": {
"apiUrl": "http://test.somecompany.com/api"
},
"prod": {
"apiUrl": "http://www.somecompany.com/api"
}
}
configure variablize task:
grunt.initConfig({
/* ... */
variablize: {
target: {
input: "resources/Config.json",
output: "dist/Config.js",
variable: "Config",
property: grunt.option('profile')
}
}
});
run grunt --profile=test, and use it this way:
$(document).ready(function(){
var myURL = Config.apiUrl;
});
This might not be the best way to do it. But this works. :)
You can set value to a javascript variable with your server side code itself.
$(document).ready(function(){
var myURL = "<%=urlFromServer%>"; //Assuming you are using JSP <%= ..%>
});
This global variable holds the value. You can re use this variable wherever you need it.

Javascript Build Tools To Toggle Urls/Variables Between Production/Deployment

I am beginning my first big javascript project! I had a question about deployment. I am using ajax calls to a webservice. To set this up I have a static JS file with code like:
var API_URL_ROOT = 'http://api.example.com/';
var IN_DEVELOPMENT = True;
if (IN_DEVELOPMENT) {
API_URL_ROOT = 'http://localhost.com/api';
}
$.get(API_URL_ROOT)
I am using python/fabric to deploy. I was wondering if there were any prebuilt tools for handling the static analysis/manipulation of the javascript files., Right now it leaves toggling up to the commiters
I was planning on a deployment process like:
issue deploy command
"build" JS, by setting all values to production values (ie. IN_DEVELOPMENT = False)
Minify JS
Deploy code to production servers
I was thinking of just using sed or something to do the IN_DEVELPMENT = False replacement. I have looked at some of the popular minification tools and none seem to offer this sort of functionality.
I would assume that this is a pretty common problem for applications. How is it usually handled? Any help would be appreciated. Thank you
I recently read an article on hackernews from mozilla:
In the Mozilla Persona code base, we frequently expose difficult to
test private functions to the public interface, clearly marking the
extra functions as part of a test API. While other developers are
still able to call these private functions, the author’s intentions
are clear.
...
publicFunction: function() {
return "publicFunction can be invoked externally but "
+ privateFunction();
}
// BEGIN TESTING API
,
privateFunction: privateFunction
// END TESTING API
};
// privateFunction is now accessible via the TESTING API
function privateFunction() {
...
Code between the // BEGIN TESTING API and //END TESTING API
pseudo-markers can be removed for production during the build process.
So other companies are definitely doing this. Are there premade tools to facilitate the JS build proccess that can remove this code? I glanced at a number of their projects on github and didn't see any. Thank you
We are using dojo
And in dojo you can use conditional exclusions for the build version of your js in order to exclude parts of your code that you would not want in your build js. Hope this helps.
eg:
var API_URL_ROOT = 'http://api.example.com/';
//>>excludeStart("dev",!pragmas.dev);
var IN_DEVELOPMENT = True;
//>>excludeEnd("dev");
if (IN_DEVELOPMENT) {
API_URL_ROOT = 'http://localhost.com/api';
}
$.get(API_URL_ROOT)

Categories

Resources