I'm new to learn JS design pattern. I had a basic function before, receiving an object and do some extra actions and ouput an array.
If I use a normal basic function method, it's only few lines. However, if I use a factory method design pattern, I can get the same result, but the code amount is much bigger.
What's the benifit using a factory method design pattern? With my code, did I overuse that factory method design pattern?
Here is the Code
You can ignore the functionality of combineWithSection, the real one is more complex.
export {};
const detailBasicDetail = [
{
basicDetailA1P1: {
name: "basicDetailA1P1",
label: "basicDetailA1P1",
section: "basicDetail"
},
basicDetailA1P2: {
name: "basicDetailA1P2",
label: "basicDetailA1P2",
section: "basicDetail"
}
},
{
basicDetailA2P1: {
name: "basicDetailA2P1",
label: "basicDetailA2P1",
section: "basicDetail"
}
},
{
basicDetailA3P1: {
name: "basicDetailA3P1",
label: "basicDetailA3P1",
section: "basicDetail"
}
},
{
basicDetailA3P2: {
name: "basicDetailA3P2",
label: "basicDetailA3P2",
section: "basicDetail"
}
},
{
basicDetailA3P3: {
name: "basicDetailA3P3",
label: "basicDetailA3P3",
section: "basicDetail"
}
}
];
const detailIncidentDetail = [
{
incidentDetailA1P1: {
name: "incidentDetailA1P1",
label: "incidentDetailA1P1",
section: "incidentDetail"
}
},
{
incidentDetailA2P1: {
name: "incidentDetailA2P1",
label: "incidentDetailA2P1",
section: "incidentDetail"
},
incidentDetailA2P2: {
name: "incidentDetailA2P2",
label: "incidentDetailA2P2",
section: "incidentDetail"
}
},
{
incidentDetailA3P1: {
name: "incidentDetailA3P1",
label: "incidentDetailA3P1",
section: "incidentDetail"
}
},
{
incidentDetailA3P2: {
name: "incidentDetailA3P2",
label: "incidentDetailA3P2",
section: "incidentDetail"
}
},
{
incidentDetailA3P3: {
name: "incidentDetailA3P3",
label: "incidentDetailA3P3",
section: "incidentDetail"
}
}
];
const detailOtherDetail = [
{
otherDetailA1P1: {
name: "otherDetailA1P1",
label: "otherDetailA1P1",
section: "otherDetail"
}
},
{
otherDetailA2P1: {
name: "otherDetailA2P1",
label: "otherDetailA2P1",
section: "otherDetail"
},
otherDetailA2P2: {
name: "otherDetailA2P2",
label: "otherDetailA2P2",
section: "otherDetail"
}
},
{
otherDetailA3P1: {
name: "otherDetailA3P1",
label: "otherDetailA3P1",
section: "otherDetail"
}
},
{
otherDetailA3P2: {
name: "otherDetailA3P2",
label: "otherDetailA3P2",
section: "otherDetail"
}
},
{
otherDetailA3P3: {
name: "otherDetailA3P3",
label: "otherDetailA3P3",
section: "otherDetail"
}
}
];
const combineWithSection = (detailBasicDetail, sectionName) => {
return [...detailBasicDetail, sectionName];
};
// basic function method
const generateDetail = (detail, sectionName) => {
return combineWithSection(detail, sectionName);
};
const detailFinalBasicFromFn = generateDetail(detailBasicDetail, "basicDetail");
const detailFinalIncidentFromFn = generateDetail(
detailIncidentDetail,
"incidentDetail"
);
const detailFinalOtherFromFn = generateDetail(detailOtherDetail, "otherDetail");
console.log("detailFinalBasic_1", detailFinalBasicFromFn);
console.log("detailFinalIncident_1", detailFinalIncidentFromFn);
console.log("detailFinalOther_1", detailFinalOtherFromFn);
// factory method
abstract class Detail {
finalDetail;
constructor(public detail, public sectionName) {
this.finalDetail = combineWithSection(detail, sectionName);
}
}
abstract class Factory {
abstract combineWithSectionArray();
}
class BasicDetail extends Detail {
constructor(public detail, public sectionName) {
super(detail, sectionName);
}
}
class BasicDetailFactory extends Factory {
combineWithSectionArray() {
return new BasicDetail(detailBasicDetail, "basicDetail");
}
}
class IncidentDetail extends Detail {
constructor(public detail, public sectionName) {
super(detail, sectionName);
}
}
class IncidentDetailFactory extends Factory {
combineWithSectionArray() {
return new IncidentDetail(detailIncidentDetail, "incidentDetail");
}
}
class OtherDetail extends Detail {
constructor(public detail, public sectionName) {
super(detail, sectionName);
}
}
class OtherDetailFactory extends Factory {
combineWithSectionArray() {
return new OtherDetail(detailOtherDetail, "otherDetail");
}
}
class FinalDetail {
static generateFinalDetail(name: string) {
switch (name) {
case "basicDetail":
return new BasicDetailFactory().combineWithSectionArray();
case "incidentDetail":
return new IncidentDetailFactory().combineWithSectionArray();
case "otherDetail":
return new OtherDetailFactory().combineWithSectionArray();
default:
return null;
}
}
}
const detailFinalBasic = FinalDetail.generateFinalDetail("basicDetail");
const detailFinalIncident = FinalDetail.generateFinalDetail("incidentDetail");
const detailFinalOther = FinalDetail.generateFinalDetail("otherDetail");
console.log("detailFinalBasic_2", detailFinalBasic!.finalDetail);
console.log("detailFinalIncident_2", detailFinalIncident!.finalDetail);
console.log("detailFinalOther_2", detailFinalOther!.finalDetail);
Related
Initially at first screen,
const appLaunchedListener = Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
component: {
name: 'StartScreen',
}
}
});
});
Then, using Navigation.push(...) to new page, at this point onwards I want to start using bottomTabs.
I have tried this at NewScreen:
Navigation.setRoot({
root: {
bottomTabs: {
children: [
{
stack: {
children: [{
component: {
name: 'NewScreen',
},
}],
options: {
bottomTab: {
text: 'NEW',
icon: {
scale: 15,
uri: 'new_grey'
},
selectedIcon: {
scale: 15,
uri: 'new_gold'
},
}
},
},
},
{
stack: {
children: [{
component: {
name: 'NotificationScreen',
},
}],
options: {
bottomTab: {
text: 'NOTIFICATION',
icon: {
scale: 15,
uri: 'notification_grey'
},
selectedIcon: {
scale: 15,
uri: 'notification_gold'
},
}
},
},
},
]
}
}
});
With my codes now, the bottom tabs does not appear.
How can I achieved my expceted result?
With V1, I can just use these handler: startSingleScreenApp(...) & startTabBasedApp(...)
The codes provided already worked fine. The problem lies in where to put the codes.
You can call the Navigation.setRoot(...) again in any of your screen but it should be inside of the exported class.
Like this:
...
export default class NewScreen {
constructor(props) {
super(props);
}
startTabScreen = () => {
const tabs = [{ ... }];
Navigation.setRoot({
root: {
bottomTabs: {
children: tabs
}
}
});
}
componentDidMount() {
this.startTabScreen();
}
...
}
I am trying to make this code return each employees name.
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
getNames: function(){
return this.employees.map(this.getName)
},
delayedGetNames: function(){
setTimeout(this.getNames,500)
}
}
console.log(company.delayedGetNames());
However, when I run the code I get "TypeError: Cannot read property 'map' of undefined"
I have tried doing
setTimeout(this.getNames.bind(this),500)
I just get undefined returned to me.
Can anyone help me out?
You need to add a callback to your function in order to get the names.
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
getNames: function(){
return this.employees.map(this.getName)
},
delayedGetNames: function(cb){
setTimeout(()=>cb(this.getNames()),500)
}
}
company.delayedGetNames(names => console.log(names))
Or, using Promise, you could write something like this:
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
getNames: function(){
return this.employees.map(this.getName)
},
delayedGetNames: function() {
return new Promise(resolve => setTimeout(() => resolve(this.getNames()), 1000));
}
}
company.delayedGetNames().then(console.log);
With few tricks and getters
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
get getNames(){
console.log(this.employees.map(x => this.getName(x)));
},
get delayedGetNames(){
setTimeout(this.getNames,500)
}
}
console.log(company.delayedGetNames);
I want to watch the nested property of a json. Whenever this nested property changes call a fn().
export class HeaderComponent {
user: any;
constructor(){
this.user = {
options: [
{ name: 'Jenny Hess', img: 'assets/img/avatar/small/jenny.jpg' },
{ name: 'Elliot Fu', img: 'assets/img/avatar/small/elliot.jpg' },
{ name: 'Stevie Feliciano', img: 'assets/img/avatar/small/stevie.jpg' }
],
selected: { name: 'Jenny Hess', img: 'assets/img/avatar/small/jenny.jpg' }
}
}
Fn changes values
public changeUser(item) {
this.user.selected = item;
/*Some Code here*/
}
public customLogin(user) {
/*Some Code here*/
this.user.selected = user;
/*Some Code here*/
}
Whenever the value of this.user.selected changes call a function.
I'm using rxjx as well.
Any suggestion??
You could do something like this:
export class HeaderComponent implements OnDestroy {
user: any;
userSelectSubject: BehaviorSubject<{name: string, img: string}>;
private userSelectSubscription: Subscription;
constructor(){
this.user = {
options: [
{ name: 'Jenny Hess', img: 'assets/img/avatar/small/jenny.jpg' },
{ name: 'Elliot Fu', img: 'assets/img/avatar/small/elliot.jpg' },
{ name: 'Stevie Feliciano', img: 'assets/img/avatar/small/stevie.jpg' }
]
}
this.userSelectSubject = new BehaviorSubject<{name: string, img: string}>({ name: 'Jenny Hess', img: 'assets/img/avatar/small/jenny.jpg' });
this.userSelectSubscription = this.userSelectSubject.subscribe((newSelectedUser) => {
this.user.selected = newSelectedUser;
});
}
ngOnDestroy() {
this.userSelectSubscription.unsubscribe();
}
}
Then you just need to call this.userSelectSubject.next({...}) passing the new selected user as parameter.
I want to use mutation in Relay to change an array (not connection). The array is typed GraphQLList in the GraphQL side. The graphql side worked perfectly, but relay side needs dataID for each item in an array. And when I am inserting new item or modifying existing item in the array, there are no dataID provided? What is the right way to do this? By the way, I am using redux to maintain the list, and submit changes via relay at the end.
The schema:
let widgetType = new GraphQLInputObjectType({
name: 'Widget',
fields: () => ({
label: {
type: GraphQLString
},
type: {
type: GraphQLString
},
list: {
type: new GraphQLList(GraphQLString)
},
description: {
type: GraphQLString
},
required: {
type: GraphQLBoolean
}
})
});
let modifyFormMutation = mutationWithClientMutationId({
name: 'ModifyForm',
inputFields: {
id: {
type: new GraphQLNonNull(GraphQLString)
},
name: {
type: new GraphQLNonNull(GraphQLString)
},
userId: {
type: new GraphQLNonNull(GraphQLString)
},
widgets: {
type: new GraphQLList(widgetType)
}
},
outputFields: {
formEdge: {
type: formConnection.edgeType,
resolve: (obj) => {
return {
node: {
id: obj.id,
name: obj.name,
userId: obj.userId,
widgets: obj.widgets
},
cursor: obj.id
};
}
},
app: {
type: appType,
resolve: () => app
}
},
mutateAndGetPayload: ({
id, name, userId, widgets
}) => {
db.collection('forms').findOneAndUpdate({
_id: new ObjectID(id)
}, {
name, userId, widgets, createAt: Date.now()
});
return {
id, name, userId, widgets
};
}
})
Relay mutation:
export default class ModifyFormMutation extends Mutation {
getMutation () {
return Relay.QL`mutation{modifyForm}`;
}
getFatQuery() {
return Relay.QL`
fragment on ModifyFormPayload {
formEdge
app { forms }
}
`;
}
getCollisionKey() {
return `check_${this.props.app.id}`;
}
getConfigs() {
return [{
type: 'FIELDS_CHANGE',
fieldIDs: {
formEdge: {node: this.props.node},
app: this.props.app.id
}
}];
}
getVariables() {
return {
name: this.props.node.name,
id: this.props.node.id,
userId: this.props.node.userId,
widgets: this.props.node.widgets
};
}
getOptimisticResponse() {
return {
formEdge: {
name: this.props.node.name,
id: this.props.node.id,
userId: this.props.node.userId,
widgets: this.props.node.widgets
}
};
}
}
And error message from browser:
"Variable "$input_0" got invalid value
{"name":"asdfasdfsa","id":"57e790cec252f32aa805e38d","userId":"57e10a02da7e1116c0906e40","widgets":[{"dataID":"client:618507132","label":"sdfas","type":"text","list":[],"description":"","required":true},{"label":"sfasdfasaaa","list":[],"type":"number","description":"","required":"false"}],"clientMutationId":"0"}.↵In
field "widgets": In element #0: In field "dataID": Unknown field."
I'd like to import a helper class rather than inlining the logic inside my component. I get the following error:
http://eslint.org/docs/rules/no-unused-vars 'NavbarService' is defined but never used
/services/NavbarService.js
class NavbarService {
constructor (init) {
this.init = init;
}
static applications () {
return [
{ name: 'Administration' },
{ name: 'Standard' }
];
}
static views () {
return [
{ name: 'Providers', path: '/providers' },
{ name: 'Authorities', path: '/authorities' },
{ name: 'Services', path: '/services' },
{ name: 'Codes', path: '/codes' }
];
}
}
/components/Navbar.vue
import NavbarService from '../services/NavbarService.js';
export default {
data () {
return {
versionIsVisible: false,
version: '2.0.0',
applications: NavbarService.applications(),
views: NavbarService.views()
};
},
methods: {
showApplications: function () {
this.applications = NavbarService.applications();
this.views = [];
return;
}
}
};
Following Roy J's suggestion, I changed /services/NavbarService.js to:
export default {
applications: function () {
return [
{ name: 'Administration' },
{ name: 'Standard' }
];
},
views: function () {
return [
{ name: 'Providers', path: '/providers' },
{ name: 'Authorities', path: '/authorities' },
{ name: 'Services', path: '/services' },
{ name: 'Codes', path: '/codes' }
];
}
};