I'm using extjs6 to developing something, some of scripts is async loaded after I click a button to add a tab to tab panel, this scripts did not include in the build directory when I build my app via sencha app build. What way is right when build the application at this situation?
any help, thanks.
Depending if the scripts should be dynamic i would use the Ext.loader functionalities.
If not, simply include them in your index.html.
The dynamic way could look like this:
Ext.define('muzkatMap.Module', {
singleton: true,
loadAssets: function () {
return this.loadMapScripts();
},
filesLoaded: false,
scriptPaths: [
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css',
'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js',
'https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.1.17/leaflet-providers.js'
],
loadMapScripts: function () {
var loadingArray = [], me = this;
return new Ext.Promise(function (resolve, reject) {
Ext.Array.each(me.scriptPaths, function (url) {
loadingArray.push(me.loadMapScript(url));
});
Ext.Promise.all(loadingArray).then(function (success) {
console.log('artefacts were loaded successfully');
resolve('Loading was successful');
},
function (error) {
reject('Error during artefact loading...');
});
});
},
loadMapScript: function (url) {
return new Ext.Promise(function (resolve, reject) {
Ext.Loader.loadScript({
url: url,
onLoad: function () {
console.log(url + ' was loaded successfully');
resolve();
},
onError: function (error) {
reject('Loading was not successful for: ' + url);
}
});
});
}
});
And you simply call in you code:
muzkatMap.Module.loadAssets().then(function(){
// do something with the newly available components
})
Related
I have a Marionette.LayoutView which calls a backbone collection and fetches the data and renders based on response. Now the issue that I am facing is, this collection needs to get data from two different endpoints, both should be independent, and then return the combined result. Below is my code:
My Marionette.LayoutView
var View = Marionette.LayoutView.extend({
template: _.template(some.html),
regions: {
div1: '[data-region="div1"]',
div2: '[data-region="div2"]',
},
initialize: function () {
this.collection = new MovieCollection();
},
onRender: function () {
if (this.collection.length) {
this.div1.show(new TopMoviesByLikesView({
collection: this.collection,
movieCount: 10,
}));
this.div2.show(new TopMovieByRatingsView({
collection: this.collection,
movieCount: 10,
}));
}
},
});
module.exports = AsyncView.extend({
ViewConstructor: View,
});
My Collection
module.exports = Backbone.Collection.extend({
model: TopMovieModel,
initialize: function (response) {
let movieCollection = [];
let movieSourceOne = new TopMovieFromSourceOne();
movieSourceOne.fetch({
success: function (collection, response) {
movieCollection = [...movieCollection, ...response.data];
},
error: function (collection, response, options) {
console.info('~ Response::ERROR', collection, response, options);
}
});
let movieSourceTwo = new movieSourceTwo();
movieSourceTwo.fetch({
success: function (collection, response, options) {
movieCollection = [...movieCollection, ...response.data];
},
error: function(collection, response, options) {
console.info('~ Response::ERROR', collection, response, options);
}
});
this.collection = movieCollection;
},
The error I get is A “url” property or function must be specified is there a way where I can do this without using a url in backbone collection? Note: I want to keep two endpoints independent since I don't want the collection to fail if primary API fails.
To avoid that error with url, you should override your fetch method, to call both collections fetch instead.
function promisifyFetch(collection) {
return new Promise(function(resolve, reject) {
collection.fetch({
success() {
resolve(collection);
},
error() {
reject();
}
});
});
}
module.exports = Backbone.Collection.extend({
model: TopMovieModel,
initialize() {
this.movieSourceOne = new TopMovieFromSourceOne();
this.movieSourceTwo = new movieSourceTwo();
},
fetch(options) {
return Promise.all([
promisifyFetch(this.movieSourceOne),
promisifyFetch(this.movieSourceTwo)
]).then(([one, two]) => {
const response = [
...one.toJSON(),
...two.toJSON()
];
this.set(response, options);
this.trigger('sync', this, response, options);
});
}
});
You probably want to handle errors here aswell.
I have upgraded my gulpfile.js to gulp 4. gulp dev is working fine. But whenever I am editing any file the reload and inject tasks are entering into an endless loop.
My gulpfile.js:
var gulp = require('gulp'),
sass = require('gulp-sass'),
symlink = require('gulp-symlink'),
jshint = require('gulp-jshint'),
browserSync = require('browser-sync').create(),
concat = require('gulp-concat'),
useref = require('gulp-useref'),
replace = require('gulp-replace'),
templateCache = require('gulp-angular-templatecache'),
gulpif = require('gulp-if'),
gulpUtil = require('gulp-util'),
uglify = require('gulp-uglify'),
minifyCss = require('gulp-clean-css'),
merge = require('merge-stream'),
clean = require('gulp-clean'),
inject = require('gulp-inject'),
svgSprite = require('gulp-svg-sprite'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer');
webfonts = require('gulp-font');
/* DEV */
gulp.task('dev-serve', function () {
browserSync.init({
server: './'
});
gulp.watch('app/**/*.scss', gulp.parallel('sass'));
gulp.watch('app/**/*.html', gulp.series('inject', 'reload'));
gulp.watch('app/**/*.js', gulp.parallel('inject', 'reload'));
gulp.watch('app/images/svg-sprite/*', gulp.parallel('svg-sprite', 'reload'));
gulp.watch('app/images/**/*', gulp.parallel('reload'));
gulp.watch('app/fonts/*', gulp.parallel('reload'));
});
/* PROD */
gulp.task('prod-serve', function () {
browserSync.init({
server: './www'
});
gulp.watch('app/**/*.scss', gulp.parallel('sass', 'build-html'));
gulp.watch('app/**/*.html', gulp.parallel('inject', 'minify-scripts', 'reload'));
gulp.watch('app/**/*.js', gulp.parallel('inject', 'minify-scripts', 'reload'));
gulp.watch('app/images/**/*', gulp.parallel('copy-images', 'reload'));
gulp.watch('app/fonts/*', gulp.parallel('copy-fonts', 'reload'));
});
// SVG SPRITE
gulp.task('svg-sprite', function () {
var svgPath = 'app/images/svg-sprite/*.svg';
return gulp.src(svgPath)
.pipe(svgSprite({
shape: {
spacing: {
padding: 0
}
},
mode: {
css: {
dest: './',
layout: 'diagonal',
sprite: 'app/images/sprite.svg',
bust: false,
render: {
scss: {
dest: 'app/styles/tools/_sprite.scss',
template: 'app/styles/tools/_sprite-template.tpl'
}
}
}
},
variables: {
mapname: 'icons'
}
}))
.pipe(gulp.dest('./'));
});
// SCSS
gulp.task('sass', function (done) {
gulp.task('sass', function () {
return gulp.src('app/**/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(concat('style.css'))
.pipe(postcss([autoprefixer()]))
.pipe(gulp.dest('app'))
.pipe(browserSync.stream());
});
done();
});
// INJECT
gulp.task('inject', function () {
return gulp.src('app/index.html')
.pipe(inject(gulp.src(['app/**/*.module.js', 'app/**/*.js', '!app/vendor/**/*.js'], {read: false}), {relative: true}))
.pipe(gulp.dest('./app'));
});
// HTML
gulp.task('build-html', function () {
return gulp.src('app/index.html')
.pipe(replace('href="/app/"', 'href="/"')) // replace base href
.pipe(useref())
.pipe(gulpif('*.js', uglify().on('error', gulpUtil.log)))
.pipe(gulpif('*.css', minifyCss()))
.pipe(gulp.dest('www'));
});
// IMAGES
gulp.task('copy-images', function () {
return gulp.src(['app/images/*'])
.pipe(gulp.dest('www/images'));
});
// FONTS
gulp.task('copy-fonts', function () {
return gulp.src(['app/fonts/*'])
.pipe(gulp.dest('www/fonts'));
});
// TEMPLATES
gulp.task('bundle-templates', function () {
return gulp.src(['app/**/*.html', '!app/index.html'])
.pipe(gulpif('*.html', templateCache({module: 'jibbar'})))
.pipe(concat('templates.min.js'))
.pipe(gulp.dest('www/tmp'));
});
// COMPONENTS
gulp.task('bundle-components', function () {
return gulp.src(['app/**/*.module.js', 'app/**/*.js', '!app/vendor/**/*.js'])
.pipe(concat('script.min.js'))
.pipe(gulp.dest('www'));
});
// MERGE TEMPLATES AND COMPONENTS
gulp.task('merge-templates-and-components', gulp.parallel('bundle-templates', 'bundle-components'), function () {
return gulp.src(['www/script.min.js', 'www/tmp/templates.min.js'])
.pipe(concat('script.min.js'))
.pipe(gulp.dest('www'))
});
// MINIFY SCRIPTS
gulp.task('minify-scripts', gulp.parallel('merge-templates-and-components', 'bundle-templates', 'bundle-components'), function () {
return gulp.src('www/script.min.js')
.pipe(uglify().on('error', gulpUtil.log))
.pipe(gulp.dest('www'))
});
// CLEAN TEMP
gulp.task('clean', gulp.parallel('bundle-templates', 'bundle-components', 'merge-templates-and-components'), function () {
return gulp.src('www/tmp', {read: false})
.pipe(clean());
});
// RELOAD BROWSER
gulp.task('reload', gulp.series('inject'), function () {
browserSync.reload();
});
//COPY IFRAME
gulp.task('copy-iframe', function () {
return gulp.src('app/components/builder/iframe/*')
.pipe(gulp.dest('www/app/components/builder/iframe'));
});
//COPY TINYMCE
gulp.task('copy-tinymce', function () {
return gulp.src('app/vendor/tinymce/**/*')
.pipe(gulp.dest('www/app/vendor/tinymce'));
});
//COPY VENDOR FILES
gulp.task('copy-vendor-files', function () {
return gulp.src(['app/vendor/angular.js','app/vendor/bootstrap.css','app/vendor/tooltip.css','app/vendor/jquery.js'])
.pipe(gulp.dest('www/app/vendor'));
});
//COPY APP IMAGES
gulp.task('copy-app-images', function () {
return gulp.src(['app/images/builder-image.svg','app/images/builder-dimensions.svg','app/images/info_icon.svg'])
.pipe(gulp.dest('www/app/images'));
});
gulp.task('dev', gulp.series(
'inject',
'svg-sprite',
'sass',
'dev-serve'
));
gulp.task('prod', gulp.series(
'inject',
'sass',
'copy-iframe',
'copy-tinymce',
'copy-vendor-files',
'copy-app-images',
'build-html',
'copy-images',
'copy-fonts',
'minify-scripts',
'clean',
'prod-serve'
));
The following image shows the endless loop
Can anyone please help me to find out what I am doing wrong here.
Thanks in advance.
In addition to my comment above, this is probably a problem:
// RELOAD BROWSER
gulp.task('reload', gulp.series('inject'), function () {
browserSync.reload();
});
In your watch statements you call inject and reload, and then in the reload task you call inject first which updates your html files (timestamp if nothing else) and so the html watch is retiggered which calls inject and reload again, etc.
Just use:
// RELOAD BROWSER
gulp.task('reload', function () {
browserSync.reload();
});
and change all your watch's to gulp.series. Since you call reload last there is no need to call inject within the reload task again.
/* PROD */
gulp.task('prod-serve', function () {
browserSync.init({
server: './www'
});
gulp.watch('app/**/*.scss', gulp.series('sass', 'build-html'));
gulp.watch('app/**/*.html', gulp.series('inject', 'minify-scripts', 'reload'));
gulp.watch('app/**/*.js', gulp.series('inject', 'minify-scripts', 'reload'));
gulp.watch('app/images/**/*', gulp.series('copy-images', 'reload'));
gulp.watch('app/fonts/*', gulp.series('copy-fonts', 'reload'));
});
and do the same for your 'dev-serve' task.
[Edit to fix will only run once]
Change to:
// RELOAD BROWSER
gulp.task('reload', gulp.series('inject'), function (done) {
browserSync.reload();
done();
});
Also I'm pretty sure you need to use this form:
// RELOAD BROWSER
//--------------------------------------|
gulp.task('reload', gulp.series('inject', function (done) {
browserSync.reload();
done();
}));
// another ) at the end above too.
See how the last anonymous function is included in the gulp.series call. You need to make that change in quite a few of your tasks.
I am trying to update protractor config on the run time, because spec file are being read from external excel file.
Below is my config:
export let config = {
allScriptsTimeout: RunConfig.allScriptsTimeout,
capabilities: {
browserName: RunConfig.browser
},
directConnect: true,
baseUrl: RunConfig.baseUrl,
framework: RunConfig.framework,
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: RunConfig.defaultTimeoutInterval,
print: function () {
}
},
onPrepare() {
bot.fullScreen();
Xlsx.readExcel();
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
},
beforeLaunch() {
let spec = new Promise((resolve) => {
resolve({
specs: Xlsx.readSpecs()
});
});
},
resultJsonOutputFile: RunConfig.resultFile
}
According to this it should update config in beforeLaunch
==========================
ReadSpec Function
readSpecs() {
fs.readFile(RunConfig.runManager, (err, buf) => {
if(!err && buf) {
let wb = XLSX.read(buf, { type: 'buffer' });
let sheet = wb.Sheets[sheetNames.specs]; //reading specs
let specArr = XLSX.utils.sheet_to_json(sheet);
let spec;
specArr.forEach(element => {
spec.push(element.spec);
});
return spec;
} else {
return [];
}
});
}
I add explanation inline:
XLSX = require('xlsx');
// change readSpecs() to sync style
readSpecs() {
let wb = XLSX.readFile(RunConfig.runManager);
let sheet = wb.Sheets[sheetNames.specs]; //reading specs
let specArr = XLSX.utils.sheet_to_json(sheet);
let spec;
specArr.forEach(element => {
spec.push(element.spec);
});
return spec;
}
export let config = {
// specify value for `specs`, and it require `Xlsx.readSpecs()`
// does not return promise-like object.
specs: Xlsx.readSpecs(),
onPrepare() {
bot.fullScreen();
// you need to move Xlsx.readExcel(); to the top
// when protractor run into onPrepare() function,
// it means protractor runner had accepted your passed-in config
// the runner won't accept any changes to the config once it accepted.
// Xlsx.readExcel();
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
},
// beforeLaunch() is unnecessary
// beforeLaunch() {
// let spec = new Promise((resolve) => {
// resolve({
// specs: Xlsx.readSpecs()
// });
// });
// },
};
beforeLaunch() can't change the config yet. There is no hooks can change the config before protractor read it. The only way is to give a pre-know value to specs and not allow promise-like value.
If your Xlsx.readExcel() or Xlsx.readSpecs() return promise, you have to use another way to implement it.
You aren't using the local variable spec for anything in the beforeLaunch function. The example in the link you posted is returning the resolved promise. You need to get rid of the local variable and return the promise like this:
beforeLaunch() {
return new Promise((resolve) => {
resolve({
specs: Xlsx.readSpecs()
});
});
}
I have simple test doing login and trying to check if it's success:
describe('My Angular App', function () {
describe('visiting the main homepage', function () {
beforeEach(function () {
browser.get('/');
element(By.id("siteLogin")).click();
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
element(By.id("formLoginButton")).click().then(function() {
browser.getCurrentUrl().then(function(url){
expect(url).toContain("profile");
});
});
});
});
});
It goes well until that last part where I'm checking URL, and in Selenium Server I get:
INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('angular could not be found on the window');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
and also I get:
Failures:
1) My Angular App visiting the main homepage should login successfully
Message:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
My protractor-conf.js:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'http://localhost:8080/Mysite',
capabilities: {
'browserName': 'firefox' // muste use firefox because I can't get .click() to work in Chrome
},
specs: [
'spec-e2e/*.js'
],
framework: 'jasmine2',
jasmineNodeOpts: {
isVerbose: true,
showColors: true,
defaultTimeoutInterval: 30000
}
};
I appreciate any help on this one.
Thanks
Looks like there is a non-Angular page opened after a click. If this is the case, you need to turn the synchronization between Protractor and Angular off:
afterEach(function () {
browser.ignoreSynchronization = false;
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
browser.ignoreSynchronization = true;
element(By.id("formLoginButton")).click().then(function() {
expect(browser.getCurrentUrl()).toContain("profile");
});
});
Note that you don't need to explicitly resolve the promise returned by getCurrentUrl and can let the expect() do that for you implicitly.
You may also need to wait for the URL to change:
var urlChanged = function(desiredUrl) {
return browser.getCurrentUrl().then(function(url) {
return url == desiredUrl;
});
};
browser.wait(urlChanged("my desired url"), 5000);
I got this code from https://github.com/ccoenraets/backbone-cellar as I am trying to learn backbone.js. When I am trying to add new model to database using slim.php, it is showing 500 (Internal Server Error). But when I am trying to fetch, update, delete its working good. Why it is showing error only on adding ?
Plz help me, Thanks.
window.WineView = Backbone.View.extend({
initialize: function () {
this.render();
},
render: function () {
$(this.el).html(this.template(this.model.toJSON()));
return this;
},
events: {
"click .save" : "beforeSave",
"click .delete" : "deleteWine"
},
beforeSave: function () {
var self = this;
var check = this.model.validateAll();
if (check.isValid === false) {
utils.displayValidationErrors(check.messages);
return false;
}
// Upload picture file if a new file was dropped in the drop area
if (this.pictureFile) {
this.model.set("picture", this.pictureFile.name);
utils.uploadFile(this.pictureFile,
function () {
self.saveWine();
}
);
} else {
this.saveWine();
}
return false;
},
saveWine: function () {
var self = this;
this.model.save(null, {
success: function (model) {
self.render();
app.navigate('wines/' + model.id, false);
utils.showAlert('Success!', 'Wine saved successfully', 'alert-success');
},
error: function () {
utils.showAlert('Error', 'An error occurred while trying to add this item', 'alert-error');
}
});
},
deleteWine: function () {
this.model.destroy({
success: function () {
alert('Wine deleted successfully');
window.history.back();
}
});
return false;
}
});
I had the same problem. In your /tutorial/api directory; open index.php and look for the first line in the function addWine():
error_log('addWine\n', 3, '/var/tmp/php.log');
Comment that line:
//error_log('addWine\n', 3, '/var/tmp/php.log');
This should solve your problem, it certainly did mine.