When I make some components in my web page,I found there a so many duplicate codes,for example,in my page I want to make two charts.
THe biggest difference of them is the data store and the title,however they have many same attributes.
I do this by define a new instance of Ext.chart:
var chart1=new Ext.chart.LineChart{config1};
var chart2=new Ext.chart.LineChart{config2};
There are so many same contents in the config1 and config2,is there any ideas to avoid this?
BTW,I have thought the extend mechanism in ext,however I can not get more details about how to use it only from the ext3.2 API.
You can extend config
var config = {
// do you shared config here
}
// and apply any different/extending configs here
var config1 = Ext.apply(config, { title: "Title of config 1" }
var config2 = Ext.apply(config, { title: "Title of config 2" }
var chart1 = new Ext.chart.LineChart(config1);
var chart2 = new Ext.chart.LineChart(config2);
And if you want it even shorter:
var chart1 = new Ext.chart.LineChart(Ext.apply(config, {
title: "Title of config 1"
});
var chart2 = new Ext.chart.LineChart(Ext.apply(config, {
title: "Title of config 2"
});
Edit: With Ext.extend:
Ext.chart.LineChart = Ext.extend(Ext.chart.LineChart, {
// put your shared config in here
});
var chart1 = new Ext.chart.LineChart({
title: "Title of chart 1",
store: new Ext.data.Store({ ... });
});
var chart2 = new Ext.chart.LineChart({
title: "Title of chart 2",
store: new Ext.data.Store({ ... });
});
Related
I am working with ionic and i want to display map marker with store logo. I constructed a default marker and I have lots of store pics or logos which need to be placed within the marker show in above image. I have used cordova geolocation plugin for get current location of user.
Response array like this :
var markers = [{
storeName: "Dib Dab Extract",
profilePic: "img/dibdab.png",
address: "420 Mary Jane Way",
rating: "4",
reviews: "4379",
offer: "100 Free Coins with 1st Purchse",
lat: "53.896408",
long: "-105.991427"
}]
Custom Marker Icon :
var image = {
url: 'img/ic_map_pin_gray.png', // image is 512 x 512
scaledSize: new google.maps.Size(80, 80),
};
Marker set on map like this :
var markerPos = new google.maps.LatLng(record.lat, record.long);
// Add the markerto the map
var marker = new google.maps.Marker({
map: map,
animation: google.maps.Animation.DROP,
position: markerPos,
icon: image,
});
Issue is resolved using Custom Marker. I have done code like this and i get exact marker like i want in above question. So i posted this answer that help anyone who want custom marker like this. i have refer https://humaan.com/blog/custom-html-markers-google-maps/
// Map Initilize function
function initMap() {
var options = {
timeout: 10000,
enableHighAccuracy: true
};
$cordovaGeolocation.getCurrentPosition(options).then(function(position) {
var latLng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
var mapOptions = {
center: latLng,
zoom: 15,
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
//Wait until the map is loaded
//Load the markers
loadMarkers();
//});
}, function(error) {
console.log(error);
console.log("Could not get location");
//Load the markers
loadMarkers();
});
}
//load marker using rest api
function loadMarkers() {
CommonService.ShowLoader();
YOUR REST API SERVICE.then(function(res) {
angular.forEach(res, function(value, key) {
var record = value;
console.log(record);
var image = {
url: 'img/ic_map_pin_gray.png', // custom background image (marker pin)
scaledSize: new google.maps.Size(70, 70),
};
var markerPos = new google.maps.LatLng(record.lat, record.long);
//Add the markerto the map
var marker = new google.maps.Marker({
map: map,
animation: google.maps.Animation.DROP,
position: markerPos,
icon: image,
});
var img_src = record.profilePic;
var overlay = new CustomMarker(
markerPos,
map, {image: img_src}
);
});
}).catch(function(error, status, headers, config) {
console.log(error);
});
}
//CustomMarker function
function CustomMarker(latlng, map, args) {
this.latlng = latlng;
this.args = args;
this.setMap(map);
}
CustomMarker.prototype = new google.maps.OverlayView();
CustomMarker.prototype.draw = function() {
var self = this;
var div = this.div;
if (!div) {
div = this.div = document.createElement('img');
div.src = self.args.image;
div.className = 'marker';
div.style.position = 'absolute';
div.style.cursor = 'pointer';
div.style.width = '35px';
div.style.height = '35px';
div.style.borderRadius = '50%';
if (typeof(self.args.marker_id) !== 'undefined') {
div.dataset.marker_id = self.args.marker_id;
}
google.maps.event.addDomListener(div, "click", function(event) {
google.maps.event.trigger(self, "click");
});
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
}
var point = this.getProjection().fromLatLngToDivPixel(this.latlng);
if (point) {
div.style.left = (point.x - 18) + 'px'; // set custom (i set it as i want to set in map )
div.style.top = (point.y - 56) + 'px'; //set custom (i set it as i want to set in map )
}
};
This worked for me.
marker = new MarkerWithLabel({
position: new google.maps.LatLng(item.latitude, item.longitude),
animation: google.maps.Animation.DROP,
labelContent: "My Job Location",
labelAnchor: new google.maps.Point(10, 38),
labelClass: "markLabelsJob", // the CSS class for the label
labelInBackground: false,
icon: 'img/active-job-pin.png',
map: map
});
I'm trying to get some data from the node server, which works fine, but when I try to GET data via the Backbone fetch (or sync), the request fails. I noticed that, for some reason, actual request is wrong: 'GET http://localhost:3000/socket.io/1/' where it should be 'GET http://localhost:3000/cars', since '/cars' is the value of the URL field that Backbone uses by convention for these operations. These are the relevant modules:
var Backbone = require("backbone");
var Car = require('models/car');
var Cars = Backbone.Collection.extend ({
model: Car,
url: '/cars',
// Unselect all Car Cards
resetSelected: function() {
for (var i=1; i<=this.length; ++i) {
var carcard=this.get(i);
carcard.set({"selected": false});
console.log(carcard.attributes.name + ' unselected');
}
},
// Select a specific model from the collection
selectByID: function(id) {
this.resetSelected();
var carcard = this.get(id);
carcard.set({"selected": true});
console.log(carcard.attributes.name + " selected");
return carcard.attributes.id;
}
});
module.exports = Cars;
And a model:
var Backbone = require("backbone");
var Car = Backbone.Model.extend({
defaults: {
year: 2011,
brand: "Brand",
model: "Model",
name: "Car Name",
pictureFle: "img/car.jpg",
kmTraveled: 0,
litresSpent: 0,
selected: false
},
});
module.exports = Car;
I tried to populate the collection like this:
var cars = new Cars();
cars.fetch();
but, as I explained, failed. Any ideas what the problem could be?
I have a Backbone App with 3 model which have nested collections:
Models Structure:
Layout extends Backbone.Model
-> sections: new Sections extends Backbone.Collection
Section extends Backbone.Model
-> rows: new Rows extends Backbone.Collection
Now if I have two section model in layout and I go and add row model to one of the Section.rows collection, it is adding it to both sections.
BTW, I am adding it from a view on an event.
Thanks in Advance.
got a workaround. I could reproduce your workflow by adding defaults property to my models.
like this:
var Section = Backbone.Model.extend({
defaults: {
rows: new Rows
}
});
var Layout = Backbone.Model.extend({
defaults: {
sections: new Sections
}
});
then really, if i add new row to rows to one of my section its appear to adding to all sections rows collection. So i do this (rude example):
var Row = Backbone.Model.extend({
defaults: {
rowData: 0
}
});
var Rows = Backbone.Collection.extend({
model: Row
});
var Section = Backbone.Model.extend({
//defaults: {
// rows: new Rows
//}
});
var Sections = Backbone.Collection.extend({
model: Section
});
var Layout = Backbone.Model.extend({
//defaults: {
// sections: new Sections
//}
});
var LayoutView = Backbone.View.extend({
});
var lView = new LayoutView({ model: new Layout });
lView.model.set('sections',new Sections());
var sections = lView.model.get('sections');
sections.add({id: 1, name: 's1',rows: new Rows() });
sections.add({id: 2, name: 's2',rows: new Rows() })
var rows = sections.get(1).get('rows');
rows.add({id:'r1',rowsData: 10});
console.log(lView.model.toJSON());
#aleha you are right the issue is of the default attribute settings in Model. As they share the same memoery space(javascript: pass by reference not by value ).
So what I did is in the initialize function
initialize: function() {
this.set( 'rows', new Rows() );
}
So, no need to do it like you are doing above:
sections.add({id: 1, name: 's1',rows: new Rows() });
Hence resolved and automate :)
Thanks for the help though.
im learning BackboneJs using the documentation and a book called "Beginning backbone".
But I have been stuck at the sorting collections part for hours.
Also tried to research but I find the results complicated =/
I know I have to use the comparator, as shown in the documentation but I don't understand how to apply it to the current code syntax-wise
http://backbonejs.org/#Collection-comparator
var Book = Backbone.Model.extend({
defaults:
{
title: "default title",
author: "default author",
pages: 20
},
comparator: function(item)
{
//sort by title
return item.get('title');
}
});
var book1 = new Book({ title:"Book of wonders",author:"author1",pages:1 });
var book2 = new Book({ title:"Zelda",author:"author2",pages:2 });
var book3 = new Book({ title: "Drake's out", author: "author3",pages:3});
var book4 = new Book({ title: "AutoCad",author: "author4",pages: 4});
var Library = Backbone.Collection.extend({
model: Book
});
var library = new Library([book1,book2]);
library.add([book3,book4]);
library.forEach(function(model){
console.log('Book is called '+model.get("title"));
});
console.log('Library contains '+library.length+' books');
This is a working solution, it will sort everything by title.
to sort it by anything else just change the parameter of the get function inside the comparator function
var Book = Backbone.Model.extend({
defaults:
{
title: "default title",
author: "default author",
pages: 20
}
});
var book1 = new Book({ title:"Book of wonders",author:"author1",pages:1 });
var book2 = new Book({ title:"Zelda",author:"author2",pages:2 });
var book3 = new Book({ title: "Drake's out", author: "author3",pages:3});
var book4 = new Book({ title: "AutoCad",author: "author4",pages: 4});
var Library = Backbone.Collection.extend({
model: Book,
initialize: function()
{
console.log("new collection");
},
comparator: function(a,b)
{
//sort by title
return a.get('title') < b.get('title') ? -1 : 1;
}
});
var library = new Library([book1,book2]);
library.add([book3,book4]);
library.sort();
library.forEach(function(model){
console.log('Book is called '+model.get("title"));
});
console.log('Library contains '+library.length+' books');
Well basically im looking on this problem, i have many components with dinamic stuff that is written in the server side with PHP.
Depending on the user my components will change, based on the role of the user.
So i need to know any ways/examples/info on how to do this.
1- I used the load function EXTJS has, but it clearly says i wont load script only plain text.
2- i used eval() but im a bit scared o this approach, like this example crate layout component (static)
var contentPanel = new Ext.Panel({
frame: true,
style: {marginTop: '10px'},
height: 315,
border: true,
bodyBorder: false,
layout: 'fit',
id: 'contentPanel'
});
var mainPanel = new Ext.Panel({
title: 'Panel Principal',
id: 'mainPanel',
border: true,
frame: true,
width: '50%',
style: {margin: '50px auto 0 auto'},
height: 400,
renderTo: Ext.getBody(),
items: [
{
html: 'Panel 1'
},
{
html: 'Panel 2'
},
contentPanel
]
})
and update the content of the layout with js files written on the server
function receiveContent(options, success, response)
{
var respuesta = response.responseText;
//console.log(respuesta);
eval(respuesta);
//console.log(options.url);
url = options.url;
url = url.substring(0,(url.search(/(\.)/)));
var contenedor = Ext.getCmp('contentPanel');
contenedor.removeAll();
var contenido = Ext.getCmp(url);
contenedor.add(contenido);
contenedor.doLayout();
}
function requestContent(panel)
{
//panel es el nombre del archivo que quiero
Ext.Ajax.request({
url: panel+'.js',
callback: receiveContent
});
}
any other way for this to be done, what i DONT want to do is making a million different components and load them ALL at login time like many people seem to say
To address your questions:
The .load method WILL load script and evaluate it once the content has finished loading, however to accomplish this you will need to set the scripts:true option, an example may be:
my_panel.load({
url: 'url_to_load.php/hmt/html/asp...',
params: {param1: param1value, param2: param2value...etc},
nocache: true,
timeout: 30,
scripts: true
});
Using eval() is fine...but seeing as the scripts:true config option above accomplishes this for javascript in the source file, you shouldnt need to use this.
Hope this helps
You might load JavaScript dynamically using something like like below - there are a hundred variations on the web. In this way, you would avoid the AJAX call and handling the response (and subsequent eval).
var aHeadNode = document.getElementById('head')[0];
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = "someFile.js";
aHeadNode.appendChild(oScript);
What I understood from your question is that, you are looking for dynamic JS file loader with a callback handler i.e. the callback function will be called only when the file is loaded fully. I also faced similar problems at start and after searching a lot and doing some research, I developed the following code, it provides absolute Dynamic JS and CSS file loading functionality :
Class ScriptLoader: (Put it in a separate file and load it at first)
ScriptLoader = function() {
this.timeout = 30;
this.scripts = [];
this.disableCaching = false;
};
ScriptLoader.prototype = {
processSuccess : function(response) {
this.scripts[response.argument.url] = true;
window.execScript ? window.execScript(response.responseText) : window
.eval(response.responseText);
if (response.argument.options.scripts.length == 0) {
}
if (typeof response.argument.callback == 'function') {
response.argument.callback.call(response.argument.scope);
}
},
processFailure : function(response) {
Ext.MessageBox.show({
title : 'Application Error',
msg : 'Script library could not be loaded.',
closable : false,
icon : Ext.MessageBox.ERROR,
minWidth : 200
});
setTimeout(function() {
Ext.MessageBox.hide();
}, 3000);
},
load : function(url, callback) {
var cfg, callerScope;
if (typeof url == 'object') { // must be config object
cfg = url;
url = cfg.url;
callback = callback || cfg.callback;
callerScope = cfg.scope;
if (typeof cfg.timeout != 'undefined') {
this.timeout = cfg.timeout;
}
if (typeof cfg.disableCaching != 'undefined') {
this.disableCaching = cfg.disableCaching;
}
}
if (this.scripts[url]) {
if (typeof callback == 'function') {
callback.call(callerScope || window);
}
return null;
}
Ext.Ajax.request({
url : url,
success : this.processSuccess,
failure : this.processFailure,
scope : this,
timeout : (this.timeout * 1000),
disableCaching : this.disableCaching,
argument : {
'url' : url,
'scope' : callerScope || window,
'callback' : callback,
'options' : cfg
}
});
}
};
ScriptLoaderMgr = function() {
this.loader = new ScriptLoader();
this.load = function(o) {
if (!Ext.isArray(o.scripts)) {
o.scripts = [o.scripts];
}
o.url = o.scripts.shift();
if (o.scripts.length == 0) {
this.loader.load(o);
} else {
o.scope = this;
this.loader.load(o, function() {
this.load(o);
});
}
};
this.loadCss = function(scripts) {
var id = '';
var file;
if (!Ext.isArray(scripts)) {
scripts = [scripts];
}
for (var i = 0; i < scripts.length; i++) {
file = scripts[i];
id = '' + Math.floor(Math.random() * 100);
Ext.util.CSS.createStyleSheet('', id);
Ext.util.CSS.swapStyleSheet(id, file);
}
};
this.addAsScript = function(o) {
var count = 0;
var script;
var files = o.scripts;
if (!Ext.isArray(files)) {
files = [files];
}
var head = document.getElementsByTagName('head')[0];
Ext.each(files, function(file) {
script = document.createElement('script');
script.type = 'text/javascript';
if (Ext.isFunction(o.callback)) {
script.onload = function() {
count++;
if (count == files.length) {
o.callback.call();
}
}
}
script.src = file;
head.appendChild(script);
});
}
};
ScriptMgr = new ScriptLoaderMgr();
Now it can be used this way:
For CSS files loading :
ScriptMgr.loadCss([first.css', 'second.css']);
That is you just need to provide css files path in an array and pass that array to loadCss() function as an argument. No callback is required for CSS files.
For JS file loading :
ScriptMgr.load({
scripts : ['lib/jquery-1.4.2.min.js','lib/jquery.touch-gallery-1.0.0.min.js'],
callback : function() {
//Here you will do those staff needed after the files get loaded
},
scope : this
});
In this case, the same way you entered CSS files, here you just need to put that array of JS files in scripts option. The callback function is called only when all the JS files are loaded successfully. Also, if in any case, the JS files are already loaded in the browser (i.e. already this code is run once), then the control will automatically go to the callback function.