If I have a store, like this example:
var myStore = Ext.create("Ext.data.Store", {
model: "User",
proxy: {
type: "ajax",
url : "/users.json",
reader: {
type: "json",
rootProperty: "users"
}
},
autoLoad: true
});
I want to cache the users.json file in the application cache, so I add it to app.json as follows:
/**
* Used to automatically generate cache.manifest (HTML 5 application cache manifest) file when you build
*/
"appCache": {
/**
* List of items in the CACHE MANIFEST section
*/
"cache": [
"index.html",
"users.json"
],
/**
* List of items in the NETWORK section
*/
"network": [
"*"
],
/**
* List of items in the FALLBACK section
*/
"fallback": []
},
Looking in Chrome developer tools, I can see that the .json file has been added to the application cache correctly, along with index.html.
I would expect this to 'just work' offline. Unfortunately it doesn't, it tries to request the json file, which doesn't work as it is offline, and then it no longer uses that data in the application.
The rest of the application works perfectly fine. Any ideas?
Found the solution from looking into the API documentation and doing a bit of trial and error with properties. It is not obvious at all.
The problem was, the requests for the .json files was being appending with additional arguments, ?dc=XXXXXXX and paging arguments. There are two additional properties that need to be applied to the proxy: noCache and enablePagingParams. This did the trick.
var myStore = Ext.create("Ext.data.Store", {
model: "User",
proxy: {
type: "ajax",
url : "/users.json",
noCache: false,
enablePagingParams: false,
reader: {
type: "json",
rootProperty: "users"
}
},
autoLoad: true
});
I also needed to update the header comment on my test cache.manifest file, to ensure that the changes to the stores were detected correctly, as I kept getting Loader errors. This isn't a problem once you use sencha CMD to build the production version as it auto-generates the application cache file for you.
NOTE: I did already have the following, widely documented, in my app.js file as well:
Ext.Loader.setConfig({
disableCaching: false
});
Hope this helps someone!
Related
So some quick background on the site's current setup:
My company's site currently runs off of a CMS. All pages are generated and routed via the CMS, so there are no .html files anywhere. It's all generated via razor (.cshtml), the CMS as a backend/data-store, and routing is handled through the CMS.
If it were up to me I'd rewrite the entire thing, but I don't have that luxury. I'm doing my best to rewrite the site with a Vue.js + webpack front-end wherever possible and slowly rebuild this site over time using more modern techniques than are currently implemented.
However, I'm running into a problem setting up Webpack's dev server with our current configuration.
I think I know what the problem is, however I'm having difficulty understanding the http-proxy-middleware's configuration settings.
I believe the way I currently have everything setup, the dev server is proxying everything - therefore not picking up any changes I make to the .vue/.js files I modify (via hot reloading).
Unfortunately I HAVE to proxy the majority of the site (pages [.cshtml files], legacy scripts, various APIs, etc.), however I don't want to proxy MY .js files and .vue files (you can assume anything of mine is in /dist/ or /src/. Everything else is the old site and must be proxied via "my.server".
Additionally, I set this up as a quick test via vue cli's webpack-simple configuation - however I can also set it up via the non-simple variation if needed. I started with "-simple" to "K.I.S.S" (Keep it simple stupid) and slowly layer on the complexity as desired.
Here's my webpack.config.js file as it currently stands:
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this nessessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true,
proxy: {
'/': {
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}
}
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
As far as I can tell the issue lies in the proxy:
proxy: {
'/': {
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}
}
Obviously the '/' is targeting everything, but while I can find plenty of examples of how to proxy specific sections and not anything else, I need the opposite. I need to proxy everything EXCEPT /dist/ and /src/. Any help would be greatly appreciated - and who knows, I may be way off here and this isn't even my problem.
Ultimately, though, the issue is when I run the dev server, if I setup proxying, everything on the site runs except my .vue files - if I don't proxy the server, nothing runs except my .vue files. Therefore it stands to reason the proxying simply needs to be applied to the legacy portions only and not the vue portions - but if I'm way off base, that's the ultimate issue and I'm open to solutions of any kind.
Thanks in advance for any insight anyone can provide!
webpack-dev-server allows you to configure multiple proxy configurations.
Using this style of configuring the proxy will give access to more advanced context filtering via the context option.
You can use globbing:
proxy: [{
context: ['**', '!/src/**', '!/dist/**', '!**/*.vue'],
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}]
Or you can write your own filtering logic.
proxy: [{
context: function(pathname, req) {
// exclude /src/ and /dist/
return !pathname.match("^/(src|dist)/");
},
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}]
sources:
https://github.com/chimurai/http-proxy-middleware#context-matching
https://github.com/webpack/webpack-dev-server/issues/562#issuecomment-241736936
https://github.com/webpack/webpack-dev-server/blob/ee9181ca3ae40d35f8e419123423df51f2f40700/examples/proxy-hot-reload/webpack.config.js#L4
I'm using ExtJs 5.1.1 and I've written a simple view with a grid, and selecting one row the corresponding model property are editable in some text fields.
When editing is completed the button 'save' call Model.save() method, which use the rest proxy configured to write the changes on the server.
The call made by the proxy are two, first is OPTIONS call to know which method are allowed, second call is a PUT.
My problem is PUT json contains only the changed attributes.
I would like that my application sends all the attributes in PUT, instead only the changed subset.
Is this a proxy configuration, or should I use another kind of proxy, like ajax?
Some code snippet:
Model:
Ext.define('myApp.model.CvModel', {
extend: 'Ext.data.Model',
alias: 'viewmodel.cv',
idProperty : 'code',
proxy: {
type: 'rest',
url: 'http://localhost:8080/CV/resource/rest/cvs/CodeSystem/Domain',
paramsAsJson: true,
reader: {
type: 'json',
rootProperty: 'Test_data'
}
},
fields: [{
...
Controller:
onSave: function () {
var selCv = this.getViewModel().get('selectedCv');
selCv.save();
....
You need to specify a writer config on your proxy with writeAllFields: true. By default it's false, and the default writer itself is just {type: 'json'}.
This is my model
Ext.define('ThemeApp.model.peopleModel', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id' },
{ name: 'subject' },
{ name: 'description'}
],
proxy: {
type: 'rest',
format: 'json',
limitParam:"",
filterParam: "",
startParam:'',
pageParam:'',
url:'http://localhost:3000/issues/1',
/*
api: {
read : 'http://localhost:3000/issues'
},*/
headers: {'Content-Type': "application/json" },
//url : 'http://api.soundcloud.com/tracks?q=allah%20dita%20rehman%20khan&client_id=0b19b8dc2526b43eae19f03b2eab6798&format=json&_status_code_map[302]=200',
reader: {
type: 'json',
rootProperty:'issues'
},
writer: {
type: 'json'
}
}});
This is my store:
Ext.define('ThemeApp.store.peopleStore', {
extend: 'Ext.data.Store',
model: 'ThemeApp.model.peopleModel',
storeId: 'peopleStore',
pageSize: 500,
autoLoad: true });
All I am trying to do is to fill this grid using Rest proxy, and to test GET and POST methods of rest proxy. I was able to ready soundcloud api using this application but when I tried to read Redmine issues (localhost:3000/issues.xml)
I am getting this error:
http://localhost:3000/issues.json just Look like http://www.redmine.org/issues.json only with lesser data. Also Localhost:300/issue.json do exsist !
Any Idea ?
You are trying to perform CORS requests against the Redmine API. Unfortunately, Redmine currently doesn't support CORS, so this is not possible without further infrastructure changes (which might compromise security if done incorrectly).
There are plugins adding CORS headers to Redmine reponses, but from what I have seen yet, they do not fully ensure a secure system yet.
Given these restrictions, your requests to Redmine will only be valid if your ExtJS app is served from the same host and port as Redmine so that it runs in the same origin and thus works without any explicit CORS support. You could enable this by using a proxy server (e.g. nginx) before both Redmine and the static files of your ExtJS app so ensure the same origin.
http://localhost:3000/issues.json
exists, but
http://localhost:3000/issues/1.json
does not exist.
In order to get a rest api to work, you need to use url rewriting.
If you have a flat .json file, you should not use a rest proxy but a json proxy, and you will not have this problem.
i'm using solr+haystack(django plugin) on the backend and the search is working fine;
While Django(and Haystack) with its templates is doing everything for me(I mean its pretty simple to configure and use), ExtJS4 is a little more complex;
The question is how to use Solr using ExtJS4?
An example is very much appreciated;
Thanks for any help and sorry for my English;
As ExtJS4 is a MVC framework, the solution is done like MVC;
The controller/Search.js
Ext.define('yourapp.controller.Search',{
extend:'Ext.app.Controller',
stores:[
'Searches'
],
views:[
'search.Search',
'search.SearchList'
],
models:[
'Search'
],
init:function(){
this.control({
"search":{
'keyup':this.search,
},
});
},
search:function(inputedTxt, e, eOpts){
this.getSearchesStore().load({
//When sending a request, q will rely to request.POST['q'] on server-side;
//inputedTxt.getValue() -- a value, entered in textfield (or whatever)
params:{
q:inputedTxt.getValue()
},
callback:function(result){
if(result[0]){
//do something with the result
//i'd been creating a window with a grid inside. "Grid"'s view is written below.
}
}
}
});
The models/Search.js
Ext.define('yourapp.model.Search',{
extend:'Ext.data.Model',
fields:[
{name:'name', type:'string'}
]
});
The store/Searches.js
Ext.define('yourapp.store.Searches',{
extend:'Ext.data.Store',
storeId: "searchStore",
model:'yourapp.model.Search',
autoLoad: false,
proxy:{
type:'ajax',
// server-side url
url: '/searchlist/',
actionMethods:{create: "POST", read: "POST", update: "POST", destroy: "POST"},
reader:{
type:'json',
root:'searches'
}
}
});
The view/search/Search.js
//a Text field to input text;
Ext.define('yourapp.view.search.Search',{
extend:'Ext.form.field.Text',
alias: 'widget.search',
id: "searchView",
enableKeyEvents: true,
initComponent:function(){
this.callParent(arguments);
}
});
The view/search/SearchList.js
//a view for a result
Ext.define('yourapp.view.search.SearchList',{
extend: 'Ext.grid.Panel',
alias:'widget.searchlist',
title: 'search result',
store: 'Searches',
columns:[
{
header:'Name',
dataIndex:'name',
flex:1
}
]
});
Somewhere in the view/Viewport.js xtype: 'search', should be inserted for a text field to be displayed.
That's all for a ExtJS4 part.
On server-side -- Django:
'haystack' and Solr should be installed and configured (by 'configured' i mean: search should already work on the server-side);
In someapp/view.py
def searchlist(request):
from haystack.query import SearchQuerySet
# POST["q"] should be receivedt from our client-side
searchText = request.POST["q"]
sqs = SearchQuerySet().filter(name=searchText)
data = []
for result in sqs:
data.append({"name": result.object.name})
return HttpResponse('{ success:true, searches:'+simplejson.dumps(data)+'}', mimetype = 'application/json')
Finally in your urls.py you should add:
(r'^searchlist/','someapp.views.searchlist'),
That was for it. Best wishes.
P.S.
I know this is not the greatest answer and there's lack of explanation, but as for me, I rather prefer a code example than verbal explanation.
SOLR has JSON output from its queries using wt=json param and can readily be consumed by ExtJS.
http://wiki.apache.org/solr/SolJSON?action=fullsearch&context=180&value=jsonp&titlesearch=Titles#JSON_Response_Writer
if you need to use jsonp you can specify a callback function via this param json.wrf=callback
I have a JSONStore like :
OrdersStore = Ext.extend(Ext.data.JsonStore, {
constructor: function(cfg) {
cfg = cfg || {};
OrdersStore.superclass.constructor.call(this, Ext.apply({
storeId: 'ordersStore',
url: '/ajaxSupport.action',
root: 'rows',
baseParams: {
action: 'getorderlegsearchgrid'
},
fields: [
{
name: 'orderId'
}
]
},
cfg));
}
});
new OrdersStore();
This store is attached to a grid : 'pendingOrdersGrid'.
When I do:
alert(Ext.util.JSON.encode(this.pendingOrdersGrid.getStore().getAt(0)));
I hope to get the first record. But I get 'null'
I can't give you a complete answer from this information but some hints:
don't extend a store with a fixed storeId, url or fields! That's really bad design
if possible use browser that supports a console (Firefox with firebug or IE with developer toolbar [or FF4/IE9]) and debug the content of your store in the console.
to read the content of a record try something like this.pendingOrdersGrid.getStore().getAt(0).data.orderId