How to create static parameters for use in data stores with rest proxy - rest

I have an ExtJS 5.1.2 app that utilizes throughout the app a global config set of parameters defined in app_dir/app/Application.js, that looks like:
launch: function () {
Ext.Loader.setConfig({enabled: true});
// Static parameters
cardioCatalogQT.config = {
mode: 'test', // switch to control use of staging or production server
//protocol: 'https://',
protocol: 'http://',
//host: 'production_server',
//host: 'test_server,
host: '127.0.0.1:5000',
apiGetQ: '/get_query/',
//apiGetQ: '/api/get_query/',
apiWriteQ: '/remote_query_put',
apiReadQ: '/remote_query_get',
//apiMedsMenu: '/api/meds',
//apiMedsMenu: '/meds',
remove: 'none'
};
// TODO - Launch the application
Ext.onReady(function () {
});
}
This way, I only have one place to change the parameters that make up the url in Ajax calls, (in this case protocol, host and apiGetQ, for example give mr the ability to set url = cardioCatalogQT.config.protocol + cardioCatalogQT.config.host + cardioCatalogQT.config.apiGetQ), in one place to change the server address from development -> testing -> production, instead of having to find all references throughout the app.
However, due to the way that the ExtJs loads, I cannot use these config parameters in data stores that use rest proxies, since these stores seem to load before items in the Ext.Loader.
For example, I have the following store:
Ext.define('cardioCatalogQT.store.Diagnoses', {
extend: 'Ext.data.Store',
alias: 'store.Diagnoses',
config:{
model: 'cardioCatalogQT.model.Diagnosis',
storeId: 'Diagnoses',
autoLoad: true,
proxy: {
type: 'rest',
url: 'http://127.0.0.1:5000/menu/diagnoses',
//url: 'http://test_server/menu/diagnoses',
//url: 'https://prod_server/api/menu/diagnoses',
reader: {
type: 'json',
rootProperty: 'menu_test'
}
}
}
});
So, when I change from testing to development environments, for example, I have to explicitly change the n different references for url in my n stores that have rest proxies.
Is there a way to define a config object so that I can use it for these stores? I looked at some examples of a preloader, but this did not seem to have any use cases documented for a global config object, also I had tried implementing a loadmask in a preloader, but it really screwed with the behavior of my app.

I use to do like #Alexander propose, however I'll prefer the singleton way. More ExtJs/MVC like.
So just to complete, I share my version:
/**
* #class
*/
Ext.define("MyApp.config.Config", {
alternateClassName: [
'MyApp.config'
],
singleton: true,
constant: {
// ... whatever constant you need to put here
},
constructor: function() {
var constant = this.constant;
//
// here, if you need to process some stuff
// for example calculate some constant
// which depend of other constant
//
return constant;
}
});
Require in your app
// Be sure to require your class prior
// to your app classes
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
requires: [
'Ext.app.*',
// ext stuff ...
'MyApp.config.Config',
// myApp stuff ...
]
// ...
});
Example usage:
Ext.define('MyApp.store.MyStore', {
// ...
proxy: {
type: 'rest',
url: MyApp.config.remoteUrl
}
})

We had similar issues, so we have put our global ConnectionSettings object into a script tag that is in index.html, before Ext.
<script type="text/javascript">
ConnectionSettings = {
...
...
};
</script>
<!-- The line below must be kept intact for Sencha Cmd to build your application -->
<script id="microloader" ...
That way, the object is available wherever we need it in our Ext code.

Related

What's the equivalent of Angular Service in VueJS?

I want to put all my functions that talk to the server and fetch data into a single reusable file in VueJS.
Plugins don't seem to be the best alternative. Template less components..?
In total there are 4 ways:
Stateless service: then you should use mixins
Stateful service: use Vuex
Export service and import from a vue code
any javascript global object
I am using axios as HTTP client for making api calls, I have created a gateways folder in my src folder and I have put files for each backend, creating axios instances, like following
myApi.js
import axios from 'axios'
export default axios.create({
baseURL: 'http://localhost:3000/api/v1',
timeout: 5000,
headers: {
'X-Auth-Token': 'f2b6637ddf355a476918940289c0be016a4fe99e3b69c83d',
'Content-Type': 'application/json'
}
})
Now in your component, You can have a function which will fetch data from the api like following:
methods: {
getProducts () {
myApi.get('products?id=' + prodId).then(response => this.product = response.data)
}
}
As I assume you want to re-use this method in multiple components, you can use mixins of vue.js:
Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.
So you can add a method in mixin and it will be available in all the components, where mixin will be mixed. See following example:
// define a mixin object
var myMixin = {
methods: {
getProducts () {
myApi.get('products?id=' + prodId).then(response => this.product = response.data)
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin]
})
// alternate way to have a mixin while initialising
new Vue({
mixins: [myMixin],
created: function () {
console.log('other code')
}
})
I'm using Vue Resource mostly.
1.I create new file where I do connection to API endpoint using Vue.http.xxx.So let's say we have endpoint that output the posts.Create new directory in your project, I call it services, and then create file called PostsService.js - content looks like this:
import Vue from 'vue'
export default {
get() {
return Vue.http.get('/api/posts)
}
}
Then I go to component where I want use this service, and import it
import PostsService from '../services/PostsService'
export default {
data() {
return {
items: []
}
},
created() {
this.fetchPosts()
},
methods: {
fetchPosts() {
return PostsService.get()
.then(response => {
this.items = response.data
})
}
}
}
For more info about this approach, feel free to check my repo on GitHub https://github.com/bedakb/vuewp/tree/master/public/app/themes/vuewp/app
I suggest creating an API Provider that you can access from anywhere in your app.
Simply create a src/utils folder and inside of it a file called api.js.
In it, export your wrapper that knows how to communicate with your API as an object or a ES6 static class (I prefer how the latter looks and works if you're not afraid of classes). This provider can use any HTTP request library that you like and you can easily swap it later by changing a single file (this one) instead of hunting down the whole codebase. Here's an example of using axios, assuming we have a REST API available at api.example.com/v1 that uses SSL:
import axios from 'axios'
import { isProduction, env } from '#/utils/env'
const http = null // not possible to create a private property in JavaScript, so we move it outside of the class, so that it's only accessible within this module
class APIProvider {
constructor ({ url }) {
http = axios.create({
baseURL: url,
headers: { 'Content-Type': 'application/json' }
})
}
login (token) {
http.defaults.headers.common.Authorization = `Bearer ${token}`
}
logout () {
http.defaults.headers.common.Authorization = ''
}
// REST Methods
find ({ resource, query }) {
return http.get(resource, {
params: query
})
}
get ({ resource, id, query }) {
return http.get(`${resource}/${id}`, {
params: query
})
}
create ({ resource, data, query }) {
return http.post(resource, data, {
params: query
})
}
update ({ resource, id, data, query }) {
return http.patch(`${resource}/${id}`, data, {
params: query
})
}
destroy ({ resource, id }) {
return http.delete(`${resource}/${id}`)
}
}
export default new APIProvider({
url: env('API_URL') // We assume 'https://api.example.com/v1' is set as the env variable
})
Next, in your main.js file or wherever else you bootstrap the Vue app, do the following:
import api from '#/src/utils/api'
Vue.$api = api
Object.defineProperty(Vue.prototype, '$api', {
get () {
return api
}
})
Now you can access it anywhere in your Vue app as well as anywhere you import Vue itself:
<template>
<div class="my-component">My Component</div
</template>
<script>
export default {
name: 'MyComponent',
data () {
return {
data: []
}
},
async created () {
const response = await this.$api.find({ resource: 'tasks', query: { page: 2 } })
this.data = response.data
}
}
</script>
or:
// actions.js from Vuex
import Vue from 'vue'
export async function fetchTasks ({ commit }) {
const response = await Vue.$api.find({ resource: 'tasks', query: { page: 2 } })
commit('SAVE_TASKS', response.data)
return response
}
Hope this helps.
I think for your simple question the answer could be any ES6 module containing functions (equivalent to methods in class in ANgular) and directly importing them in components using ES6 imports and exports. There are no such services that could be injected in components.
You can make your own service where you can place all your HTTP server calls and then import that to the components where you want to use them.
Best is to make use of Vuex for complex state management applications because in Vuex you are able to handle all async calls via actions which always run asynchronously and then commit the mutation once you have the result.Mutation will directly interact with the state and will update it in an immutable manner (which is preferred). This is stateful approach.
There are other approaches as well. But these are the ones which I follow in my code.

Sencha Touch: How to build a restful proxy url syntax?

Defined as a model and its associations, I wish the http calls to follow best practices of restful. For example, if I make the call
user.posts();
I wish to run a call http defined as
users/1/posts
If a call is then put on post with id 32 then the url of reference must be
users/1/posts/32
So I want to avoid using the filter property as is the default for a get
/posts.php?filter=[{"property":"user_id","value":1}]
This is because the api rest are already defined and I can not change them.
I would like to build a minimally invasive solution and reading on various forums the best way is to do an ovveride the method buildURL the proxy rest but was not able to retrieve all the data needed to build the final URL. Can anyone give me an example?
thanks
Try the following:
window.serverUrl = "192.168.1.XX"
var service = "login.php"
var dataTosend: {
username:"xx",
password: "yy"
}
var methode:"POST" / "GET"
this.service(service,methode,dataTosend,onSucessFunction,onFailureFunction);
onSucessFunction: function(res) {
alert("onSucessFunction"):
},
onFailureFunction: function(res) {
alert("onFailureFunction"):
},
service: function(svc, callingMethod, data, successFunc, failureFunc) {
Ext.Ajax.request({
scope: this,
useDefaultXhrHeader: false,
method: callingMethod,
url: window.serverUrl + svc,
params: data,
reader: {
type: 'json'
},
failure: failureFunc,
success: successFunc
});
I hope this will solve your problem...

Why the port number is cut when angular app call rest service

I have rest service:
http://localhost:3000/api/brands
When I test it from web browser it works well.
I use it in angular service:
var motoAdsServices = angular.module('motoAdsServices', ['ngResource']);
motoAdsServices.factory('Brand', ['$resource', function($resource) {
return $resource('http://localhost:3000/api/:id', {}, {
query: {
method: 'GET',
params: {
id: 'brands'
},
isArray: true
}
});
}]);
When it is call I have error because in reqest URL I don't have port number:
Request URL: http://localhost/api/brands
Why the port numer is is cut? Angular cut it?
In Angular doc is written:
A parametrized URL template with parameters prefixed by : as in /user/:username. If you are using a URL with a port number (e.g. http://example.com:8080/api), it will be respected.
UPDATE
I use angular version 1.0.8 (thank #KayakDave for your attention) but Angular doc applies to version 1.2.
It has a colon and therefore gets stripped, kind of like :id. If you escape it, you should be ok. Try http://localhost\:3000/api/:id instead. You may run into this again in routes or other places.
There is an issue regarding this behavior in case something changes.
Updated: http://localhost\\:3000/api/:id
Because angular intercept the url and consider the :any as a parameter that you should pass to it.
An easy way to hack this is to put \:3000 in your url.
motoAdsServices.factory('Brand', ['$resource', function($resource) {
return $resource('http://localhost:3000\:3000/api/:id', {}, {
query: {
method: 'GET',
params: {
id: 'brands'
},
isArray: true
}
});
}]);
Quick fix for the resource plugin issue:
var fixedTargetUrl = TARGET_URL.replace(/(:\d{4})/, "\\$1");

require.js synchronous loading

I'd like to define a module which computes a new dependancy, fetches it and then returns the result. Like so:
define(['defaults', 'get_config_name'], function(defaults, get_config_name) {
var name = get_config_name();
var config;
require.synchronous([configs / '+name'], function(a) {
config = defaults.extend(a);
});
return config;
});
Is there a way to do this or a better way to attack this problem?
You may try to use synchronous RequireJS call require('configs/'+get_config_name()), but it will load a module synchronously only if it is already loaded, otherwise it will throw an exception. Loading module/JavaScript file synchronously is technically impossible.
UPD: It's possible (see Henrique's answer) but highly unrecommended. It blocks JavaScript execution that causes to freezing of the entire page. So, RequireJS doesn't support it.
From your use case it seems that you don't need synchronous RequireJS, you need to return result asynchronously.
AMD pattern allows to define dependencies and load them asynchronously, but module's factory function must return result synchronously. The solution may be in using loader plugin (details here and here):
// config_loader.js
define(['defaults', 'get_config_name'], function(defaults, get_config_name) {
return {
load: function (resourceId, require, load) {
var config_name = 'configs/' + get_config_name();
require([config_name], function(config) {
load(defaults.extend(config));
})
}
}
});
// application.js
define(['config_loader!'], function(config) {
// code using config
});
If get_config_name() contains simple logic and doesn't depend on another modules, the better and simpler is calculating on the fly paths configuration option, or in case your config depends on context - map configuration option.
function get_config_name() {
// do something
}
require.config({
paths: {
'config': 'configs/' + get_config_name()
}
});
require(['application', 'defaults', 'config'], function(application, defaults, config) {
config = defaults.extend(config);
application.start(config);
});
Loading JavaScript synchronously is NOT technically impossible.
function loadJS(file){
var js = $.ajax({ type: "GET", url: file, async: false }).responseText; //No need to append
}
console.log('Test is loading...');
loadJS('test.js');
console.log('Test was loaded:', window.loadedModule); //loadedModule come from test.js

Custom PhoneGap Plugin (iOS) Function Issue

I'm using this tutorial to create a custom PhoneGap plugin:
http://wiki.phonegap.com/w/page/36753496/How%20to%20Create%20a%20PhoneGap%20Plugin%20for%20iOS
I have had success using the author's example, but I have a few questions that I have not been able to find out the answers to.
When the JavaScript function is created, the code is:
var MyPlugin = {
nativeFunction: function(types, success, fail) {
return PhoneGap.exec(success, fail, "PluginClass", "print", types);
}
};
Is there a way to set this up without var MyPlugin = {...}; and nativeFunction? In other words, can we define a function of our plugin like myfunc = function()...
Secondly, assuming there is a way to do the above, could this code:
MyPlugin.nativeFunction(
["HelloWorld"] ,
function(result) {
alert("Success : \r\n"+result);
},
function(error) {
alert("Error : \r\n"+error);
}
);
(which is the test code to test the plugin) also be written in a more standardized way? I.e., just a call to Javascript function without the nativeFunction part?
I would very much appreciate any input, thank you!
the phonegap documentation for plugins sucks. Honestly I had a bunch of issues when trying to create my own. A few tips :
the reason for doing
var MyPlugin = {};
is because this allows us to us scope things specific to that js object.
example:
MyPlugin.myFunction();
My favorite method to create plugins, similar to your question, is to prototype them
var MyPlugin = {}; // our object
MyPlugin.prototype.myFunction = function(success,fail,types){
}
The key to making a plugin fire is this -
PhoneGap.exec(success,fail,"MyPlugin","myFunction",types);
But something that they leave out is, what if we want to have options to our plugin? What if we want to do more than pass a string, then the example doesn't work. The fix is easy but not talked about at all.
var MyPlugin = {};
MyPlugin.prototype.myFunction = function(success,fail,options){
var defaults = {
foo: '', // these are options
bar: '',
};
// this parses our "options"
for(var key in defaults) {
if(typeof options[key] !== "undefined") defaults[key] = options[key];
}
return PhoneGap.exec(success,fail,"MyPlugin","myFunction",[defaults]);
}
when we call this with out javascript -
var foo = MyPlugin.myFunction(success,fail,{
foo:'hello',
bar:'world'
});
You'll notice that most of the phonegap API uses this syntax, which I found strange that their documentation didn't really talk about how to do this.
I have a post about a plugin I create you can check it out for reference.
Blog - http://www.drewdahlman.com/meusLabs/?p=138
Git - https://github.com/DrewDahlman/ImageFilter