I'm developing an angular app.I will demonstrate the problem using small code snippets for clarity.
My Component
export class MyComponent extends BaseComponent {
isuserActive = false;
...
}
Base Component
export class BaseComponent {
...
constructor() {
this.route.data.subscribe((values: Object = {}) => {
this['isuserActive'] = values['isuserActive'];
...
});
...
}
}
Routes
... data { isuserActive: true, ...
But finally when I check MyComponent, its isuserActive is false which is wrong.
But it works fine (isuserActive is true) when my component is as follows (that I don't prefer).
My Component
export class MyComponent extends BaseComponent {
isuserActive; // no initial value (I don't prefer this way)
}
So how can I solve this.
Related
I have some code on react that should re-render the main page when I click. but it does not work. Can someone suggest an idea?
/store/index.js
import jsonObjects from './jsonObjects';
class RootStore {
constructor() {
this.jsonObjects = new jsonObjects(this);
}
}
export default RootStore;
/store/jsonObjects.js
import sciences from '../data/sciences.json'
class JsonObjects {
jsonObjectsList = observable(JSON.parse(sciences))
get jsonObjects() {
return this.jsonObjectsList.filter(jsonObjects => jsonObjects.deleted === false);
}
handleClick() {}
}
decorate(JsonObjects, {
handleClick: action,
jsonObjects: computed
})
export default JsonObjects;
I've a injectable service (EntityApi) which extends a class (BaseApi). In my spec I like to mock the BaseApi with BaseApiStub. But it vain. Always calling the EntityApi.
// class
export class BaseApi { // want to mock BaseApi
constructor(injector: Injector) {
console.log("Should not be here...");
}
}
// service
#Injectable()
export class EntityApi extends BaseApi {
constructor(injector: Injector) {
super(injector, "entity");
}
}
// component
#Component({
selector: 'rt-entity-list',
templateUrl: './entity-list.component.html',
})
export class EntityListComponent {
api: any;
constructor(public entityApi: EntityApi) {
this.api = entityApi;
}
}
// mock api
export class BaseApiStub { //mocked api
constructor() {
console.log("You are on track!!")
}
get() { }
}
// spec
describe('EntityListComponent', () => {
let component: EntityListComponent;
let fixture: ComponentFixture<EntityListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [EntityListComponent],
providers: [ { provide: BaseApi, useClass: BaseApiStub }, // mocked class.
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
beforeEach(() => {
fixture = TestBed.createComponent(EntityListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Expected Behavior is, while compile component in spec. It should call the BaseApiStub, instead it is calling BaseApi. I've seen a solution as below. But no luck.
export class BaseApiStub extends BaseApi { }
Test Code: stackblitz Check the console. I expect the You are
on track!! log but received as Should not be here...
Not able to progress further. Can someone correct my mistake please.
What you are trying to do does not work. Dependency injection and class inheritance are not directly related. This means you cannot switch out the base class of your service like this.
As I see it you have two ways on how to do this.
Option 1:
Instead of mocking your BaseApi and providing the mock in your test you need to mock your EntityApi and provide this mock in your test.
Option 2:
Instead of letting your EntityApi extend from BaseApi, you could keep BaseApi a simple service and provide it as a dependency.
Instead of
class EntityApi extends BaseApi {
constructor(private injector: Injector) {
you do
class EntityApi {
constructor(private api: BaseApi) {
If you setup your EntityApi like this, it does not extend from BaseApi, but rather has it as a dependency. Then you can create a mock of the BaseApi and provide it like you did in your test.
Edit
Regarding your comment:
Since I should be using methods from BaseApi I cannot go without extends.
This is not true. Let's say the BaseApi has a method foo() that you want to use. When you extend your baseclass, the usage might look like this:
class EntityApi extends BaseApi {
constructor(private injector: Injector) {}
exampleMethod() {
this.foo();
}
}
If you just have the dependency you can still call the method like this:
class EntityApi {
constructor(private api: BaseApi) {}
exampleMethod() {
this.api.foo();
}
}
You don't need to extend from BaseApi in order to call methods on it.
In case you need to mock a method of a parent class (e.g for Directive) you can do that through the stub extension of the tested class.
spyObject = {
methodToSpyOn(){}
};
#Directive({selector: '[myDirective]'})
class MyStubDirective extends MyDirective {
parentMethodToMock() {
return spyObject.methodToSpyOn();
}
}
spyOn(spyObject, 'methodToSpyOn').and.returnValue(true);
This approach is usually needed if your class has the parent method calls in constructor
I have a bunch of components with methods like these
class Header extends Component {
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
I'd like to move this duplicate code to a function such as
function toggleBodyClass(className, e) {
e.preventDefault();
document.body.classList.toggle('sidebar-mobile-show');
}
Then refactor the functions above like so
sidebarMinimize(e) {
toggleBodyClass('sidebar-minimized', e);
}
In the past, I would have used a mixin, but the React docs now discourage their use.
Should I just put this function in a regular JavaScript module and import it in the component modules, or is there a particular React construct for reusing code across components?
You could make a High Order Component with those functions as so:
import React, { Component } from 'react';
export default function(ComposedComponent) {
return class ExampleHOC extends Component {
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
render()
return <ComposedComponent { ...this.props } />;
}
}
}
Then take whatever component you wish to augment with those properties by wrapping them in the HOC:
ExampleHOC(Header);
Should I just put this function in a regular JavaScript module and import it in the component modules
Yes. That would be a pretty standard way to share code between JavaScript files. I don't believe you need to or should do anything React-related to achieve this.
However, it is important to understand that you shouldn't directly interact with the DOM ever from a React component. Thanks #ShubhamKhatri for the heads up.
In my opinion, you are correct in putting the function in a regular JavaScript module and import it in the component modules.
Since a typical answer OOP answer would be to create another class extending React.Component adding that function. Then extend that class so every component you create will have that function but React doesn't want that.
One thing to verify that you are correct is in this pattern I believe.
https://reactjs.org/docs/composition-vs-inheritance.html
inherence solve your problem , create new class that extends Component and extend from your new class to share functionality and reduce the code
class SuperComponent extends Component
{
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
---------------------------------------------------------------------
class Home extends SuperComponent
{
someMethod()
{
this.sidebarMinimize();
}
}
class Main extends SuperComponent
{
someMethod()
{
this.sidebarToggle();
}
}
Other Solution
create utils class and use it in your component
class UIUtiles
{
static sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
static sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
class Home extends SuperComponent {
someMethod(e) {
UIUtiles.sidebarToggle(e);
UIUtiles.sidebarMinimize(e);
}
}
I have a problem introducing TypeScript to our JavaScript project.
First I want to use TypeScript only in my part of the code, leaving the JavaScript untouched.
Now I try to use a JavaScript class in my TypeScript code, but I don't find a solution in the last days.
The head of my TypeScript class with import of the JavaScript:
import { BaseLogic } from "../baseLogic";
export class ClaimLogic extends BaseLogic {
...
The JavaScript class ("baseLogic.js"):
module.exports = class BaseLogic {
constructor(meta, logger) {
...
My *.d.ts file ("baseLogic.d.ts"):
export class BaseLogic {
meta: any;
log: any;
constructor(meta: any, logger: any)
}
The head of the compiled JavaScript:
const baseLogic_1 = require("../baseLogic");
class ClaimLogic extends baseLogic_1.BaseLogic {
...
As you see in the compiled JavaScript baseLogic_1.BaseLogic is used.
This results in following error:
TypeError: Class extends value undefined is not a constructor or null
With only baseLogic_1 after the extends keyword in the JavaScript file all is fine.
I have no idea about a solution and hope you can help me!
Your import suppose to be import * as BaseLogic from "../baseLogic";.
In that way you will get the Class that you put on module.exports.
The codesnipet in baseLogic.js exports the class.
module.exports = class BaseLogic {
constructor(meta, logger) {
...
}
You try to access with class ClaimLogic extends baseLogic_1.BaseLogic an object that includes the class BaseLogic
Solution
import BaseLogic from '../baseLogic'
// or: const BaseLogic = require("../baseLogic");
class ClaimLogic extends BaseLogic {
...
}
ES7 introduces the concept of static property and method definitions. Along with an ES7-capable transpiler, these can be used in React to specify validators and defaults for props, like so:
export default class ComponentOne extends React.Component {
static propTypes = {
foo: React.PropTypes.string
}
static defaultProps = {
foo: 'bar'
}
// ...
}
This is super handy, but gets tricky when subclasses come into play. For example, say the following module is added to the same codebase as ComponentOne above:
export default class ComponentTwo extends ComponentOne {
static propTypes = {
baz: React.PropTypes.number
}
static defaultProps = {
baz: 42
}
// ...
}
I'd like ComponentTwo to "inherit" the property validators and defaults of its superclass, ComponentOne. Instead, propTypes and defaultProps on ComponentTwo shadow those on ComponentOne, and React tosses out those defined on ComponentOne.
Since super is a reference to the current class's prototype, and static is supposed to reference values hung directly off the prototype, I thought this might work:
import _ from 'lodash';
export default class ComponentTwo extends ComponentOne {
static propTypes = _.merge(super.propTypes, {
baz: React.PropTypes.number
});
}
However, this generates an error, presumably from Babel: Parsing error: 'super' outside of function or class.
This works, but is not very portable:
export default class ComponentTwo extends ComponentOne {
static propTypes = Object.assign({
baz: React.PropTypes.number
}, ComponentOne.propTypes);
}
Are there any other ways to do this more cleanly/reusably?
I stumbled upon this question, and it's been almost 3 years, but who know, someone might need it. (And it's still relevant)
Given that when you extend a class it automatically inherits of its parent class, you would not need to overwrite the static propTypes property.
Given a parent class:
class Parent {
static propTypes = {
parentProp: PropTypes.string
}
}
If you don't want to add other propTypes/defaultProps, you can simply:
class Children extends Parent {
// Do not declare the propTypes, it will extends by itself.
}
console.log(Children.propTypes); // Will output an object with parentProp in it
If you want to explicitly tell that you extends Parent propTypes, or add new propTypes:
class Children extends Parent {
static propTypes = {
...Parent.propTypes, // Yes, you can spread static properties like everything else
childProp: Proptypes.number,
}
}
Small note, for this to work properly with Babel, you might need to include the transform-es2015-classes babel plugin in your plugins or preset. My .babelrc:
"presets": [
["env", {
"include": ["transform-es2015-classes"]
}],
"stage-0",
"react"
],
Hope this helps!
Curiously enough, using super works for static methods. I'd think it should work for static properties too. To me, then, it feels more natural to use the super class name directly:
export default class ComponentTwo extends ComponentOne {
static propTypes = _.merge({}, ComponentOne.propTypes, {
baz: React.PropTypes.number
});
}
But, to use super, one workaround I can think of is using a static method to initialize the property, which unfortunately would have to be called manually:
class ComponentTwo extends ComponentOne {
static _init() {
this.propTypes = _.merge({}, super.propTypes, {
baz: React.PropTypes.number
});
}
}
ComponentTwo._init();