I was trying to implement a Builder pattern in Javascript using modularity, where I got caught in a circular dependencies-like situation. My file structure looks something like this,
index.js
import PersonBuilder from "./PersonBuilder.js";
let pb = new PersonBuilder();
let person = pb.lives.in('jaipur').at('ajmer Road')
.age.of(32).build();
Person.js
class Person
{
constructor()
{
this.city = this.street = this.name = "";
this.age = 0;
}
toString(){
return `${this.name} from ${this.city} lives at ${this.street} is ${this.age} years old`;
}
}
export default Person;
PersonBuilder.js
import Person from "./Person.js";
import PersonAgeBuilder from "./PersonAgeBuilder.js";
import PersonAddressBuilder from "./PersonAddressBuilder.js";
class PersonBuilder
{
constructor(person = new Person)
{
this.Person = person;
}
get lives()
{
return new PersonAddressBuilder(this.person);
}
get age()
{
return new PersonAgeBuilder(this.person);
}
build()
{
return this.person;
}
}
export default PersonBuilder;
PersonAddressBuilder.js
import PersonBuilder from "./PersonBuilder.js";
class PersonAddressBuilder extends PersonBuilder
{
constructor(person)
{
super(person);
}
in(city){
this.person.city = city;
return this;
}
at(street)
{
this.person.street = street;
return this;
}
}
export default PersonAddressBuilder;
PersonAgeBuilder.js
import PersonBuilder from "./PersonBuilder.js";
class PersonAgeBuilder extends PersonBuilder
{
constructor(person)
{
super(person);
}
of(age){
this.person.age = age;
}
}
export default PersonAgeBuilder;
When I am calling index.js on my browser I got the following error:
Uncaught ReferenceError: Cannot access 'PersonBuilder' before initialization
at PersonAgeBuilder.js:4
how can I solve this?
Related
I am very new in making game and pixijs, I am having a trouble in render stage.
This is my code, I have draw function to render in baseScreen, and I use it by code
this.screens[i].draw();
in screenManage, and I don't know why I can not render the stage on canvas.
There are no error notice but I do not see the loadBackground file.
Thank you so much for all the help.
game.js
import ScreenManager from '../framework/screens/screenManager.js';
export default class Game
{
constructor()
{
this.frames = 0;
}
init()
{
this.screenManager = new ScreenManager(this);
this.screenManager.loadContent();
this.screenManager.draw();
}
}
screenManager.js
import LoadingScreen from './loadingScreen.js';
export default class ScreenManager
{
constructor(game)
{
this.game = game;
this.screens = new Array();
this.canvas = PIXI.autoDetectRenderer(1024, 768);
document.body.appendChild(this.canvas.view);
}
loadContent()
{
this.loadingScreen = new LoadingScreen('loadingScreen');
this.loadingScreen.loadContent();
this.addScreen(this.loadingScreen);
}
addScreen(screen)
{
this.screens.push(screen);
}
draw()
{
for(var i=0;i<this.screens.length;i++)
{
console.log(this.screens[i]);
this.screens[i].draw();
}
}
baseScreen.js
export default class BaseScreen
{
constructor(name, screenManager)
{
this.name = name;
this.sm = screenManager;
this.stage = new PIXI.Container();
}
// Render
draw()
{
this.sm.canvas.render(this.stage);
}
}
loadingScreen.js
import BaseScreen from './baseScreen.js';
export default class LoadingScreen extends BaseScreen
{
constructor(name, screenManager)
{
super(name, screenManager);
}
loadContent()
{
this.loadBackground = PIXI.Sprite.from('assets/images/Preloader.png');
this.stage.addChild(this.loadBackground);
}
}
in index.js I have.
import PageLoader from './pageLoader';
$(function() {
const pageLoader = new PageLoader();
});
and pageloader.js
class PageLoader{
constructor(){
{
this.customer = null;
this.data = [];
this.init();
}
}
init() { }
}
module.exports = PageLoader;
everything works fine. but if I import a class from page loader.
import Customer from './customer';
class PageLoader{
constructor(){
{
this.customer = null;
this.data = [];
this.init();
}
}
init() { }
}
module.exports = PageLoader;
and customer.js
class Customer{
constructor(){
this.data = [];
this.init();
}
init() {
}
}
module.exports = Customer;
I receive
WARNING in ./src/index.js 10:23-33 "export 'default' (imported as
'PageLoader') was not found in './pageLoader'
module.exports
syntax is from Modules (which are largely used in NodeJs - the counterpart of it is require rather than import). If you want to use import, you need to use export clause, which is from es6 modules
export default PageLoader
you could also do named exports
export { PageLoader };
and then
import { PageLoader } from './pageLoader';
Further reading
I have a generic function that I would like to get the name of the class that is passed in.
public addComponent<T extends Component>(): Component {
comp = new Component() as T;
comp.name = T.constructor.name;
console.log(comp.name);
return comp;
}
Then lets say I call it like so:
obj.addComponent<MyClass>();
I would then expect the log to display "MyClass". But currently I get an error saying:
Cannot find name 'T'.
There's no way to do that.
The T doesn't exist at runtime, it's only for compilation and the compiler removes that (along with the types) so the resulting javascript for this:
class MyFactory {
public addComponent<T extends Component>(): Component {
let comp = new Component() as T;
comp.name = T.constructor.name;
console.log(comp.name);
return comp;
}
}
Is:
var MyFactory = (function () {
function MyClass() {
}
MyFactory.prototype.addComponent = function () {
var comp = new Component();
comp.name = T.constructor.name;
console.log(comp.name);
return comp;
};
return MyFactory;
}());
As you can see, the js code doesn't have the generics signature, so there's no definition for T, and so T.constructor results in the error you're receiving.
If you want the method to create an instance of a class by passing it then it should look like:
interface ComponentConstructor<T extends Component> {
new(): T;
name: string;
}
class Component {
name: string;
}
class MyComponent extends Component {}
class MyFactory {
public addComponent<T extends Component>(ctor: ComponentConstructor<T>): Component {
let comp = new ctor();
comp.name = ctor.name;
console.log(comp.name);
return comp;
}
}
let factory = new MyFactory();
let obj = factory.addComponent(MyComponent as ComponentConstructor<MyComponent>);
(code in playground)
when i export a class as 'export default AvatarStore;' versus 'export default new AvatarStore();' i get the following error trying to use its methods in other classes... Is using the new syntax correct?
here is the code:
import { List } from 'immutable';
import EventEmitter from 'events';
import Utils from '../utils/Utils.js'
import RestService from '../services/RestService'
import RestCallStatus from '../constants/RestCallStatus'
import Avatar from '../models/Avatar'
const CHANGE_EVENT = 'change';
const TAG = 'AvatarStore';
class AvatarStore extends EventEmitter {
constructor() {
super();
this._populateRestCallStatus = RestCallStatus.NOT_REQUESTED;
this._populated = false;
this._dataStore = List();
}
populate(){
RestService.getAllAvatars(this.handleSuccess.bind(this), this.handleFailure.bind(this));
this._populateRestCallStatus = RestCallStatus.STARTED
}
handleSuccess(serviceName, jsonData){
Utils.logMethod(TAG, 'handleSuccess ' + serviceName);
if(jsonData.length > 0){ this._dataStore = List().clear(); }
jsonData.forEach((entity) => {
this._dataStore = this._dataStore.push(new Avatar(entity))
});
this._populated = true;
this._populateRestCallStatus = RestCallStatus.SUCCESS;
this.emitChange();
}
handleFailure(serviceName, error){
Utils.logMethod(TAG, 'handleFailure');
this._populateRestCallStatus = RestCallStatus.FAILED
console.error(`Server call ${serviceName} failed with error: ${serviceName}!`)
}
getItems(){
//Utils.logMethod(TAG, 'getItems');
return this._dataStore;
}
getItemById(itemId){
return Utils.findArrayElementById(this._dataStore, itemId);
}
getPopulated(){
return this._populated;
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
emitChange() {
Utils.logMethod(TAG, 'emitChange');
this.emit(CHANGE_EVENT);
}
}
export default new AvatarStore();
export default AvatarStore means that you want to export class. in export default new AvatarStore() case, you export instance of class (object). So you need to use the one it makes sense in your case - use the first if you want to have more instances of AvatarStore, otherwise you can use the second one.
Of course in the first case you need to make new instance somewhere after you import it.
In my TaskController.php I have:
namespace Api;
use Repos\EnquiryRepo;
class TaskController extends \BaseController {
protected $repo;
function __construct() {
parent::__construct();
$this->repo = new EnquiryRepo();
}
public function show($enquiryId)
{
if(!$enquiry = $this->repo->findById($enquiryId)) {
return $this->json('That does not exist.', 404);
}
return \View::make('task.index', ['enquiry' => $enquiry]);
}
}
I am totally lost as to how I can pass the $enquiry model into my react store:
EnquiryStore.js
import { EventEmitter } from 'events';
export default class EnquiryStore extends EventEmitter {
constructor() {
super();
this.enquiries = new Map();
this.loading = false;
}
handleEnquiriesData(payload) {
payload.data.enquiries.forEach((enquiry) => {
this.enquiries.set(enquiry.id, enquiry);
});
this.loading = false;
this.emit('change');
}
handleReceiving() {
this.loading = true;
this.emit('loading');
}
getEnquiries() {
return this.enquiries;
}
dehydrate () {
return this.enquiries;
}
rehydrate (state) {
}
}
EnquiryStore.handlers = {
'RECEIVED_ENQUIRIES_DATA': 'handleEnquiriesData',
'RECEIVING_ENQUIRIES_DATA': 'handleReceiving'
};
EnquiryStore.storeName = 'EnquiryStore';
Would I need to somehow echo it out into a JS variable or something? How can I get this to work? The whole point is so that when the page loads I have all the data already and React/Fluxible doesn't need to make another request for the data.
After a bit of trail and error I got it working:
In my Laravel view I did:
#extends('layouts.react')
#section('css')
{{HTML::style('/css/task.css?bust=' . time())}}
#stop
#section('js')
<script>
app_dehydrated.context.dispatcher.stores.EnquiryStore = {{$enquiry}}
</script>
#stop
Then my store:
import { EventEmitter } from 'events';
export default class EnquiryStore extends EventEmitter {
constructor() {
super();
this.enquiry = {};
this.loading = false;
}
handleReceiving() {
this.loading = true;
this.emit('loading');
}
getEnquiry() {
return this.enquiry;
}
dehydrate () {
return this.enquiry;
}
rehydrate (state) {
this.enquiry = state;
}
}
EnquiryStore.handlers = {
'RECEIVED_ENQUIRIES_DATA': 'handleEnquiriesData',
'RECEIVING_ENQUIRIES_DATA': 'handleReceiving'
};
EnquiryStore.storeName = 'EnquiryStore';
If there is a better way please tell me! Hope this helps others.