How To Get Constant Inside ui-router (Angular) state function - angularjs

I want to reference a "constant" that is defined outside this state function but if I try to pass it in as a provider it errors because constants are not providers. That is, I want to do something like:
var exports = module.exports = function ($stateProvider,configData) { ...
But that fails. How can I get my javascript variable baseDirectory passed in.
The bigger problem is that the webroot is not always at the same url. sometimes it is /ng and sometimes it is just / and I want to be able to set that as a config someplace I can load into a config file (not hard code into the state function.
var exports = module.exports = function ($stateProvider) {
$stateProvider.state('home', {
url: baseDirectory + '/home',
templateUrl: '/templates/home/home.html',
controller: 'HomeController',
});
};
exports.$inject = ['$stateProvider'];

I got the same issue, what I did, is to build a constant in the app, and replace them with new value in gulp task when the base url changed.
It had many apps, so my idea is dumb and simple, just find and replace the value of the content in the app by the new value input from gulp task configuration.
It's not smart, but works.
In the example, I have three apps in /clinic, /panel, /company, and for each of them, it had a build.js in it.
The build.js will build the app, and replace the constant value.
I have many apps, so I do this:
var gulp = require('gulp');
var concat = require('gulp-concat');
var taskBuildClinic = require("./clinic/build");
var taskBuildPanel = require("./panel/build");
var taskBuildCompany = require("./company/build");
var migrate = require("./laravel/migrate");
var env = {
'dev': {
EndpointBaseUrl: "'/admin/public/';",
TemplateBaseUrl: "'/admin/public';"
}
};
// ./node_modules/.bin/gulp
gulp.task('clinic', function (cb) {
return taskBuildClinic(gulp, env);
});
gulp.task('company', function (cb) {
return taskBuildCompany(gulp, env);
});
gulp.task('panel', function (cb) {
return taskBuildPanel(gulp, env);
});
In each build.js located in different app, it had:
var concat = require('gulp-concat');
var replace = require('gulp-replace');
...
if (env['production']) {
// replace something not for production
endpoint = "var EndpointBaseUrl = " + env['production']['EndpointBaseUrl'];
templateBaseUrl = "var TemplateBaseUrl = " + env['production']['TemplateBaseUrl'];
console.log(endpoint);
console.log(templateBaseUrl);
} else {
endpoint = "var EndpointBaseUrl = " + env['dev']['EndpointBaseUrl'];
templateBaseUrl = "var TemplateBaseUrl = " + env['dev']['TemplateBaseUrl'];
console.log(endpoint);
}
return gulp.src(files)
.pipe(concat(prefix + '.js'))
.pipe(replace(/var EndpointBaseUrl.*?;/g, endpoint))
.pipe(replace(/var TemplateBaseUrl.*?;/g, templateBaseUrl))
.pipe(gulp.dest('./build'));
In the app, I had:
var TemplateBaseUrl = "";
var EndpointBaseUrl = "";
Their content will be replaced by the value from gulp task.

Related

GULP: rename the affected file only

I want to create a copy with a new extension in the same folder only of the file which was changed. How should src and dest be specified?
var gulp = require('gulp'),
rename = require("gulp-rename"),
watch = require('gulp-watch');
var filePath = "./repo/**/*.xml"
gulp.task('watch', function () {
watch(filePath, gulp.series('rename'));
});
gulp.task('rename', function () {
return gulp.src(???).pipe(rename(function (path) {
path.extname = ".mei";
})).pipe(gulp.dest(???));
});
Try this:
var gulp = require('gulp'),
rename = require("gulp-rename"),
watch = require('gulp-watch'),
changedInPlace = require('gulp-changed-in-place');
var filePath = "./repo/**/*.xml"
gulp.task('watch', function () {
watch(filePath, gulp.series('rename'));
});
gulp.task('rename', function () {
return gulp.src(filePath)
.pipe(changedInPlace())
.pipe(rename(function (path) {
console.log(path);
path.extname = ".mei";
}))
.pipe(gulp.dest('repo'));
});
gulp.task('default', gulp.series('rename', 'watch'));
This uses the gulp-changed-in-place plugin to only pass through files that have changed in the same directory (in your case filePath).
It does have a firstRun option but I couldn't get it to work properly - maybe that option doesn't play well with gulp v4? To work around that, rename is called once before the watch is set up, see
gulp.task('default', gulp.series('rename', 'watch'));
Now it will only change the extension of the changed file and add that changed file back into the same directory it started in.

Using LowDB on Electron APP

I'm developing a basic app made with Electron and AngularJS. For this purpose I'm using the electron boilerplate (https://github.com/szwacz/electron-boilerplate) and for database, I'm using LowDB(https://github.com/typicode/lowdb).
I have been able to create a database(JSON) and read it from a script. But my problem is when I want to update and save. I can update, and the change is reflected on the JSON file, but when I start the app again, the JSON has the same data that at the beginning (it is overwritten).
I think it is a problem with the build task of Electron boilerplate, that always overwrites the file. I thought that when I did the task to release the app, it will fixes(npm run release), but not, it overwrites the json.
I am loading the database so:
import low from 'lowdb';
import storage from 'lowdb/file-sync';
import {
remote
}
from 'electron';
var fs = require('fs');
var app = remote.require('app');
const db = low(__dirname + '/db.json', {
storage
});
document.addEventListener('DOMContentLoaded', function() {
db('users').push({
'name': 'foo'
});
});
This script is loaded at the beginning, so it should add, every time that app is started, a new entry. The script is writting the new entry in JSON file but when the start is restarted, the JSON back to the previous state.
At the end, I am using the localStorage, but I would like to use LowDB to save the data locally.
Here is the task (gulp file) that I commented before about the build of app:
'use strict';
var pathUtil = require('path');
var Q = require('q');
var gulp = require('gulp');
var sass = require('gulp-sass');
var watch = require('gulp-watch');
var batch = require('gulp-batch');
var plumber = require('gulp-plumber');
var jetpack = require('fs-jetpack');
var bundle = require('./bundle');
var generateSpecImportsFile = require('./generate_spec_imports');
var utils = require('../utils');
var projectDir = jetpack;
var srcDir = projectDir.cwd('./app');
var destDir = projectDir.cwd('./build');
var paths = {
copyFromAppDir: [
'./node_modules/**',
'./bower_components/**',
'./components/**',
'./scripts/**',
'./shared.services/**',
'./sections/**',
'./helpers/**',
'./db.json',
'./**/*.html',
'./**/*.+(jpg|png|svg|eot|ttf|woff|woff2)'
],
}
// -------------------------------------
// Tasks
// -------------------------------------
gulp.task('sass', ['clean'], function() {
console.log('Compiling SASS...');
gulp.src('app/styles/scss/main.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest(destDir.path('styles')));
});
gulp.task('watch:sass', function() {
console.log('Watching SASS...');
var sassWatcher = gulp.watch(['app/styles/scss/*.scss','app/**/**/*.scss'], ['sass']);
sassWatcher.on('change', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});
gulp.src('app/styles/scss/main.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest(destDir.path('styles')));
});
gulp.task('clean', function (callback) {
return destDir.dirAsync('.', { empty: true });
});
var copyTask = function () {
return projectDir.copyAsync('app', destDir.path(), {
overwrite: true,
matching: paths.copyFromAppDir
});
};
gulp.task('copy', ['clean'], copyTask);
gulp.task('copy-watch', copyTask);
var bundleApplication = function () {
return Q.all([
bundle(srcDir.path('background.js'), destDir.path('background.js')),
bundle(srcDir.path('app.js'), destDir.path('app.js')),
bundle(srcDir.path('script.js'), destDir.path('script.js')),
]);
};
var bundleSpecs = function () {
return generateSpecImportsFile().then(function (specEntryPointPath) {
return bundle(specEntryPointPath, destDir.path('spec.js'));
});
};
var bundleTask = function () {
if (utils.getEnvName() === 'test') {
return bundleSpecs();
}
return bundleApplication();
};
gulp.task('bundle', ['clean'], bundleTask);
gulp.task('bundle-watch', bundleTask);
gulp.task('finalize', ['clean'], function () {
var manifest = srcDir.read('package.json', 'json');
// Add "dev" or "test" suffix to name, so Electron will write all data
// like cookies and localStorage in separate places for each environment.
switch (utils.getEnvName()) {
case 'development':
manifest.name += '-dev';
manifest.productName += ' Dev';
break;
case 'test':
manifest.name += '-test';
manifest.productName += ' Test';
break;
}
// Copy environment variables to package.json file for easy use
// in the running application. This is not official way of doing
// things, but also isn't prohibited ;)
manifest.env = projectDir.read('config/env_' + utils.getEnvName() + '.json', 'json');
destDir.write('package.json', manifest);
});
gulp.task('watch', function () {
watch('app/**/*.js', batch(function (events, done) {
gulp.start('bundle-watch', done);
}));
watch(paths.copyFromAppDir, { cwd: 'app' }, batch(function (events, done) {
gulp.start('copy-watch', done);
}));
watch('app/**/scss/*.scss', batch(function (events, done) {
gulp.start('watch:sass', done);
}));
watch('app/**/**/*.scss', batch(function (events, done) {
gulp.start('watch:sass');
}));
});
gulp.task('build', ['bundle', 'sass', 'copy', 'finalize']);
How you can see, in 'copyFromAppDir' there is a db.json. This file is my database, but I want update it and changes persist, but I am not be able to do that.
Kind regards!
It looks like your gulp task 'clean' is overwriting your db.json file. Because you are using lowDB, this is the same as overwriting your database. If you remove the line './db.json', from the 'copyFromAppDir' array the changes should persist.
Like this:
var paths = {
copyFromAppDir: [
'./node_modules/**',
'./bower_components/**',
'./components/**',
'./scripts/**',
'./shared.services/**',
'./sections/**',
'./helpers/**',
'./**/*.html',
'./**/*.+(jpg|png|svg|eot|ttf|woff|woff2)'
],
}

AngularJs - get list of all registered modules

Can I get a list of all registered modules at run time?
For example:
// Some code somewhere in some .js file
var module1 = angular.module('module1', []);
// Some code in some other .js file
var module2 = angular.module('module2', []);
// Main .js file
var arrayWithNamesOfAllRegisteredModules = .....
// (result would be: ['module1', 'module2'])
Angular does not provide a way to retrieve the list of registered modules (at least I was not able to find a way in source code). You can however decorate angular.module method to store names in array. Something like this:
(function(orig) {
angular.modules = [];
angular.module = function() {
if (arguments.length > 1) {
angular.modules.push(arguments[0]);
}
return orig.apply(null, arguments);
}
})(angular.module);
Now you can check angular.modules array.
Demo: http://plnkr.co/edit/bNUP39cbFqNLbXyRqMex?p=preview
You can simply do :
console.log(angular.module('ModuleYouWantToInspect').requires);
It should return of an array of strings (dependencies). You can do the same for the output.
Given an angular.element, the $injector.modules array contains the list of registered modules.
e.g.
angular.element(document.body).injector().modules
If you're debugging, I discovered you can get the list by:
Find or add code to invoke run() from any module with any body, say:
angular.module('myModule')
.run(function() {})
Put a breakpoint on the .run, and step into angular.run(). There's an object called "modules" in scope that has all the modules as properties, by name.
This may work with other module methods too, or be accessible from code; I haven't tried very hard to understand the larger picture.
Improving solution
(function(angular) {
var orig = angular.module;
angular.modules = [];
angular.modules.select = function(query) {
var cache = [], reg = new RegExp(query || '.*');
for(var i=0,l=this.length;i< l;i++){
var item = this[i];
if(reg.test(item)){
cache.push(item)
}
}
return cache;
}
angular.module = function() {
var args = Array.prototype.slice.call(arguments);
if (arguments.length > 1) {
angular.modules.push(arguments[0]);
}
return orig.apply(null, args);
}
})(angular);
Now you can select modules:
angular.modules.select('app.modules.*')
Creating modules tree:
var app = angular.module('app.module.users', ['ui.router'...]);
var app = angular.module('app.module.users.edit', ['app.modules.users']);
Your main module app (concat submodules)
angular.module('app', ['ui.bootstrap', 'app.services', 'app.config']
.concat(angular.modules.select('app.module.*')));
in addition to #dfsq answer you can get list of modules with it dependencies
var AngularModules = (function (angular) {
function AngularModules() {
extendAngularModule();
angular.element(document).ready(function () {
getModulesDependencies();
});
}
var extendAngularModule = function () {
var orig = angular.module;
angular.modules = [];
angular.module = function () {
var args = Array.prototype.slice.call(arguments);
var modules = [];
if (arguments.length > 1) {
modules.push(arguments[0]);
}
for (var i = 0; i < modules.length; i++) {
angular.modules.push({
'module': modules[i]
});
}
return orig.apply(null, args);
};
};
var getModulesDependencies = function () {
for (var i = 0; i < angular.modules.length; i++) {
var module = angular.module(angular.modules[i].module);
angular.modules[i].dependencies = module && module.hasOwnProperty('requires') ? module.requires : [];
}
};
return AngularModules;
})(angular);
Usage:
var modules = new AngularModules();
There is a similar question with better answers here https://stackoverflow.com/a/19412176/132610, a summary of what they proposed is:
var app = angular.module('app', []);
# app.service(/**your injections*/) etc
# to access to the list of services + injections
app._invokeQueue #has following form:
[
[
'$provide',
'service',
Arguments[
'serviceName',
[
'$dependency1',
'$dependency2',
function(){}
],
]
]
]
This involves poking at implementation details that may change over time, but you can try this.
Load the page fully.
Set a breakpoint inside angular.module().
Call angular.module() from the console.
When you hit the breakpoint execute print out the modules dictionary console.dir(modules) or if you want to copy it into another editor window.prompt('', JSON.stringify(modules))
This works because behind the scenes angular builds a dictionary of the loaded modules called modules. You also want to wait until it's finished loading all the modules so they're in the dictionary.

Protractor/Jasmine do not create folder for xunit file when it does not exist

I have a protractor instance that tests my app.
The following is my config for where the jasmine.JUnitXmlReporter should write the results file.
onPrepare: function () {
require('jasmine-reporters');
var capsPromise = browser.getCapabilities();
capsPromise.then(function (caps) {
var browserName = caps.caps_.browserName.toUpperCase();
var browserVersion = caps.caps_.version;
var prePendStr = browserName + '-' + browserVersion + '-';
jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter('test-results/protractor/', true, true, prePendStr));
});
},...
This presents a bit of an interesting challenge for git, because it won't track a folder unless there is a file in it. Which means that when my CI server is working on this, the file won't get written unless I put some other dummy file there.
I've played with the permissions on the folders, and that doesn't help. Is there something I'm doing wrong here? Running karma unit tests doesn't exhibit this same problem, e.g.:
junitReporter: {
outputFile: 'test-results/unit/results.xml',
suite: ''
},
This is how JUnitXmlReporter is made. You can see it's source code here.
You can use File System module here to make the folder needed before setting up the JUnitXmlReporter
var fs = require('fs')
fs.mkdirSync('unit');
fs.mkdirSync('unit/test-results');
jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter('test-results/protractor/'..
There is also a mkdirp module in NPM for avoiding errors when folder already is there.
My solution ended up being a combination of what #Mohsen suggest above and this SO question.
Instead of using synchronous file processing I opted to use Q to turn the mkdir calls into promises. Additionally, the capsPromise appends the browser version to the output file for extra information.
onPrepare: function () {
require('jasmine-reporters');
var fs = require('fs');
var Q = require('q');
var mkdir = Q.denodeify(fs.mkdir);
mkdir('test/test-results')
.then(function(data) {
mkdir('test/test-results/protractor')
.then(function(data) {
var capsPromise = browser.getCapabilities();
capsPromise.then(function (caps) {
var browserName = caps.caps_.browserName.toUpperCase();
var browserVersion = caps.caps_.version;
var prePendStr = browserName + '-' + browserVersion + '-';
jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter('test/test-results/protractor/', true, true, prePendStr));
});
})
.fail(function(err) {
console.err('Error creating directory ' + err);
})
})
.fail(function(err) {
console.err('Error creating directory ' + err);
});
},

requirejs text plugin downloads all templates which are not required

I'm using RequireJS along with text plugin to load the Handlebar templates dynamically in Backbone Layout Manager. But on page load all the templates get downloaded instead of the specified one.
In the case shown below when I just want to render footer all the files (header, modal) gets fetched instead of only footer.tpl.
templateLoader.js
define(function (require) {
var Handlebars = require('handlebars');
var getTemplateFile = function (templateName) {
var tmpl = null;
switch (templateName) {
case 'header':
tmpl = require('text!../html/templates/header.tpl');
break;
case 'footer':
tmpl = require('text!../html/templates/footer.tpl');
break;
case 'modal':
tmpl = require('text!../html/templates/modal.tpl');
break;
}
return tmpl;
};
var _compiled = function (tpl, context) {
var compiled = Handlebars.compile(tpl);
return context ? compiled(context) : compiled;
};
return {
getTemplate: function (templateName, model) {
return _compiled(getTemplateFile(templateName), model);
}
}
});
MyView.js - LayoutManager
App.Views.StoreFooter = Backbone.Layout.extend({
beforeRender: function () {
this.$el.html(Templates.getTemplate('footer'));
}
});
When I check the resources downloaded in Chrome I see modal.tpl, header.tpl which should not be there according to above code.
This is a side-effect of the syntax sugar, described in the documentation :
define(function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
The AMD loader will parse out the require('') calls by using Function.prototype.toString(), then internally convert the above define call into this:
define(['require', 'dependency1', 'dependency2'], function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
Since it parses the function body as a string, it has no way of seeing that the require statements are inside a switch which is guaranteed to only match one case.
edit:
I thought this could be fixed by refactoring your code a bit:
var getTemplateFile = function (templateName) {
var path = null;
switch (templateName) {
case 'header':
path = 'text!../html/templates/header.tpl';
break;
case 'footer':
path = 'text!../html/templates/footer.tpl';
break;
case 'modal':
path = 'text!../html/templates/modal.tpl';
break;
}
return require(path);
};
Unfortunately, this causes:
Uncaught Error: Module name "text!blah.txt_unnormalized2" has not been loaded yet for context: _
...which makes sense when you realise this is just syntactic sugar, not a way to make RequireJS work in synchronous mode.

Resources