I'm trying to inject my config file into all of my routes, controllers, and components instead of calling import config from '../config/environment' in every file. I get the following error however:
Uncaught Error: Failed to create an instance of 'config:main'. Most likely an improperly defined class or an invalid module export.
Below is my code as its rendered via coffeescript.
// app/initializers/config.js
define('app/initializers/config', ['exports', 'app/config/environment'], function (exports, Config) {
'use strict';
var ConfigInitializer, initialize;
initialize = function (container, app) {
var config;
config = {
config: Config['default']
};
app.register('config:main', config);
app.inject('route', 'config', 'config:main');
app.inject('controller', 'config', 'config:main');
app.inject('component', 'config', 'config:main');
};
ConfigInitializer = {
name: 'config',
initialize: initialize
};
exports['default'] = ConfigInitializer;
exports.initialize = initialize;
What am I missing?
I've stepped through everything using breakpoints and my path to my environment.js file is correct. So I know its not that. I think I'm missing something fundamental about dependency injection.
Everything looks fine in your code, except one thing. By default Ember expects to register Factories but not instances. So once the property gets injected, it tries to get an instance from registered factory. But in your case it's not a factory, it's an instance (object) itself. So the only thing you have to do is to say Ember to use registered object as is, without trying to get an instance. To achive this, just add instantiate: false to register options:
app.register('config:main', config, {instantiate: false});
It is complaining that can't instantiante a new config object when initializing. Try changing your config object into a Ember.Service
import Ember from 'ember'
initialize = function(container, app) {
var config = Ember.Service.extend({
config: Config['default']
}
...
}
Related
I have a Vue.js 2 project with Typescript. In the main.ts file, I've declared 2 variables, that I've wanted to access globally in my project:
// ...
Vue.prototype.$http = http; // this is the library imported from another file, contains various methods such as `get`, `post` etc.
Vue.prototype.$urls = urls; // this is JSON object, also imported from another file
new Vue({
store,
render: (h) => h(App),
}).$mount('#app');
In one of my components, let's call it User I have following mounted code block:
mounted(): void {
this.$http.get(`${this.$urls.getUser}/${this.userId}`);
}
Everything works fine when I'm running a local server (via npm run serve command), but when I create an app build (via npm run build command) and enter the app on the server (or the index.html file on my hdd) I receive following error:
TypeError: Cannot read property 'get' of undefined
at VueComponent.value (user.ts:62) // <-- this line is the one with $http.get from `mounted` hook
I'm not sure how to proceed with this, I've blindly tried to add those global values to various places e.g. in http.d.ts file I have the following:
import { KeyableInterface } from '#/interfaces/HelperInterfaces';
import Vue from 'vue';
declare module 'vue/types/vue' {
interface VueConstructor {
$http: KeyableInterface;
}
}
declare module 'vue/types/vue' {
interface Vue {
$http: KeyableInterface;
}
}
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
http?: KeyableInterface
}
}
(I've also created urls.d.ts with similar code)
UPDATE #1:
I've tried also following approach - in my main.ts file:
const helperModules = {
/* eslint-disable-next-line #typescript-eslint/no-explicit-any */
install: (vueInstance: any) => {
vueInstance.prototype.$http = http;
vueInstance.prototype.$urls = urls;
},
};
Vue.use(helperModules);
But it still doesn't work (same error).
UPDATE #2:
I've also imported http utility into my user component, and added following console.log to existing mounted callback:
console.log(http, this.$http)
And while working on my localhost, it returns me twice the same value, but when I create a build it returns me:
ModuleĀ {__esModule: true, Symbol(Symbol.toStringTag): "Module"}, undefined
Similar thing happens, when I add console.log(urls, this.$urls) - imported module is being logged, while prototyped one returns undefined.
Any thoughts? Will appreciate any help.
Finally I've overcome the problem by moving the prototyping parts from main.ts to App.ts file.
I'm not 100% sure if it's a valid "the Vue.js way" of solving this, as I've always declared that in main.js file - but I was using then JavaScript & it was "just working" as expected.
We have a legacy Backbone application that we are moving over to React. An interim step we are attempting is loading a bundled Backbone module into a React page, until we have time to fully rewrite it. I am halfway there, I can bundle up the app and all its dependencies with r.js using a config like this:
({
...
baseUrl: './',
name: 'myapp',
paths: {
'myapp': './legacy/app'
},
out: 'src/appbuilt.js'
...
})
The module is set up like this:
define(function(require) {
var $ = require('jquery'),
_ = require('underscore'),
...
templates = $(require('text!templates/app.html')),
app = {};
app.View = .....
app.Model = .....
return app;
});
That bundle works on the Backbone side. Next I need to turn that into something I can import into React and render. I am trying things like this:
npx babel src/appbuilt.js --out-file src/appbuilt.es6.js --plugins=#babel/transform-modules-umd
Which works to give me a UMD module, but importing it like this:
import * as legacyapp from '../../appbuilt.es6';
Gives me warnings on the build like:
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
And errors on page load that are probably symptoms of something:
Uncaught TypeError: name.split is not a function
What is the secret sauce to get my module converted into something I can use? I am open to modifying how the Backbone app does its imports, or making a wrapper of some kind that is more easily translatable.
I am not sure but I can guess that the format of your AMD modules is the problem here. Try converting them to regular AMD modules:
define(
['jquery', 'underscore', 'text!templates/app.html' /* add rest of dependencies here */],
function ($, underscore, templates /** add parameters for rest of dependencies here */)
{
var app = {};
// app.View = ...
// app.Model = ...
return app;
}
);
Just converted my app to ember-cli, but I don't know how to use Ember.Application.register any more because register doesn't seem to be available when Application is started with extend rather than create.
import Ember from 'ember';
import App from 'myapp/app';
var AdminMyController = Ember.ObjectController.extend({
});
// THROWS ERROR HERE BECAUSE register isn't, uh...registered?
App.register('controller:adminMyController', AdminMyController, { singleton: false });
export default AdminMyController;
Previously, because App was a global, I could register this right in the same class.
Am I going to have to move all the register calls to an initializer so I can get access to the app instance?
I belive an initializer would do this for you. You'll need to create an initializers folder in your app directory (same level as controllers, templates, etc). This file should go there.
import Ember from 'ember';
var AdminMyController = Ember.ObjectController.extend({
...
});
export default {
name: 'adminMyController',
initialize: function (container, application) {
container.register('controller:adminMyController', AdminMyController, {singleton: false});
}
};
I am attempting to create a number of AngularJS libraries that can be re-used across apps and modules. I thought i was doing everything correctly but am still having a problem.
First I create a file that defines a generic module (app.ui) and attaches a provider (LayoutManager) to it ... (I am using a jQuery plugin called "jQuery Layout". This provider allows the app to access and manipulate the layout parameters. I don't want to get hung up on the details of the plugin however. The question is more general, but thought I should at least provide some explanation)
angular.module("app.ui", [])
.provider('LayoutManager', [function () {
'use strict';
var appLayout = $('body').layout(),
moduleNavLayout = $('.module-nav-container').layout(),
moduleLayout = $('.module-content-container').layout();
return {
$get: function () {
return {
ApplicationLayout: appLayout,
ModuleNavigatonLayout: moduleNavLayout,
ModuleContentLayout: moduleLayout
}
}
}
}]);
Then I identify the module (app.ui) as a dependency of the "app" (ListMgrApp) I want to use it in.
angular.module("ListMgrApp", ["ui.router", "app.services", "app.ui"])
Then I inject (is that the correct terminology?) the specific provider (LayoutManager) into the application ...
angular.module("ListMgrApp", ["ui.router", "app.services", "app.ui"]).
config(['$stateProvider', 'LayoutManager',
function ($stateProvider, layout) {
'use strict';
// initialization code goes here
}]);
While it appears that the code inside the LayoutManager provider DOES execute, which I believe is due to it being included as a dependency for the app, I am still getting the following error from the application when it runs.
Uncaught Error: [$injector:modulerr] Failed to instantiate module ListMgrApp due to:
Error: [$injector:unpr] Unknown provider: LayoutManager
I have verified that the source code for all required files are being successfully down loaded.
What am I missing?
RESOLUTION
Thanks elclanrs for the answer! I just wanted to add what exactly I updated to make it work.
I added "Provider" to the name of the provider (LayoutManager) in the config() method of the app (ListMgrApp). I had originally thought I was supposed to also change the name of "LayoutManager" in the provider code but misread the original solution comment. Only change the name in the app config() method. I thought I would point it out here just in case someone else was a "skimmer" and missed it.
angular.module("ListMgrApp", ["ui.router", "app.services", "app.ui"]).
config(['$stateProvider', 'LayoutManagerProvider',
function ($stateProvider, layout) {
'use strict';
// initialization code goes here
}]);
I'm building a new application using Marionette and RequireJS, and I've got the following structure:
/main.js -- Main require() call that includes app.js and calls Application.start()
/app.js -- Application definition
/modules
/sub
/controller.js -- Defines a sub-application, requires app.js
...
I'm trying to keep dependencies at the top level of each file, as opposed to using require() inline, so that the r.js compiler can find them. The problem is, in my controller.js file, I am requiring app.js (in order to add initializers) and so I cannot require controller.js in app.js until after the Application has initialized, which means I can't put controller in the top-level define() array.
A simplified example of the currently working code:
// app.js
define(['marionette'], function(Marionette) {
var Application = new Marionette.Application();
Application.on("initialize:after", function() {
require(['modules/sub/controller'], function() {
Backbone.history.start();
});
});
});
// controller.js
define(['app'], function(Application) {
Application.module('SubApplication', function(SubApplication, Application, Backbone, Marionette, $, _) {
var router = Marionette.AppRouter.extend({
appRoutes: { "foo": "bar" }
});
var controller = { foo: function() {} };
Application.addInitializer(function() {
new router({ controller: controller });
});
});
});
I'm still fairly new to both Require and Marionette, so any suggestions would be welcome! I do know that I can include the files I want via the include option to r.js, but I thought this question was worth asking nonetheless.
The way I've chosen to do it in my book on Marionette and RequireJS is to require inline the modules that are only necessary for a subset of functionality. This simplifies development, and also means that modules won't be loaded unless that code path is triggered.
R.js will find inline dependencies just fine (provided they're defined as strings, i.e. not computed dynamically). In addition, they will also work with Almond.js (but don't forget to use the findNestedDependencies option in your build file).
Hope this helps!