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' }
];
}
};
Related
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);
I know, there are already tons of same questions i saw some of them, but couldn't get full answer.
So, I have an array something like this (simplified for demonstration):
// links.js
const links = [
{
name: 'Page 1',
path: '/page-1'
},
{
name: 'Page-2',
subpages:[
{ name: 'Page (2-1)', path: '/page-2-1' },
{ name: 'Page (2-2)', path: '/page-2-2' }
]
},
{
name: 'Page 3',
path: '/page-3'
},
{
name: 'Page 4',
subpages:[
{ name: 'Page (4-1)', path: '/page-4-1' },
{ name: 'Page (4-2)', path: '/page-4-2' },
{ name: 'Page (4-3)', path: '/page-4-3' }
]
},
...
]
export default links
The above object is menu-links data, i render them on the screen for nagivating between pages and subpages is dropdown. They have either path or subpages, not both and there might be more nested.
There are 2 tasks i want help with.
First:
Every page of my site has a title and most of them is same as its name property shown above.
So, i have a function rendered on every page that returns the pathname of the current route, so what i want is to map through the links and get the name of matched path.
For example, if i give /page-4-1, i wanna get the name property of the matched path, So that is name: Page 4
Second
This time, it is something like a breadcrumb, If i give ['/page-1', '/page-2-1', '/page-4-2'], i wanna get:
[
{
name: 'Page 1',
path: '/page-1'
},
{
name: 'Page (2-1)',
path: '/page-2-1'
},
{
name: 'Page (4-2)',
path: '/page-4-2'
},
]
There will be cases where there might not be a matched result, in that case i would like to insert {name: document.body.title, path: null}
I tried
i'm using Nextjs
import { useRouter } from 'next/router'
import links from 'links.js'
const router = useRouter()
const splitted = router.asPath
.split('/')
.filter(
(sp) =>
sp !== ''
)
cost ready = []
for (let sp = 0; sp < splitted.length; sp++) {
for (let ln = 0; ln < links.length; ln++) {
if (links[ln].path) {
if (links[ln].path === '/' + splitted[sp]) {
ready.push(links[ln])
}
} else {
for (let sb = 0; sb < links[ln].sublinks.length; sb++) {
if (links[ln].sublinks[sb].path === '/' + splitted[sp]) {
ready.push(links[ln].sublinks[sb])
}
}
}
}
}
This is partly working but is messy, there should be a better ways with map, filter and find but i couldn't succeed with my tries on them.
Thank you in advance for your help!
EDIT:
Oops! my question had a big mistake, the links object only contains path key, not conditional path and link.
const links = [
{
name: 'Page 1',
path: '/page-1'
},
{
name: 'Page-2',
subpages:[
{ name: 'Page (2-1)', path: '/page-2-1' },
{ name: 'Page (2-2)', path: '/page-2-2' }
]
},
{
name: 'Page 3',
path: '/page-3'
},
{
name: 'Page 4',
subpages:[
{ name: 'Page (4-1)', path: '/page-4-1' },
{ name: 'Page (4-2)', path: '/page-4-2' },
{ name: 'Page (4-3)', path: '/page-4-3' }
]
},
];
const findPathObj = (path,links) => {
let result = null;
for(const item of links){
if(item.path == path) return item;
if(item.subpages) result = findPathObj(path, item.subpages)
if(result) break;
}
return result;
}
const findPageName = (path,links) => findPathObj(path,links)?.name;
const findBreadcrumb = (pathes, links) => pathes.map(path => findPathObj(path,links) || {name: document.title, path: null});
console.log(findPageName('/page-4-1', links));
console.log(findBreadcrumb(['/page-1', '/page-2-1', '/page-4-2'],links))
For your first question try the following
const links = [
{
name: "Page 1",
path: "/page-1",
},
{
name: "Page-2",
subpages: [
{ name: "Page (2-1)", path: "/page-2-1" },
{ name: "Page (2-2)", path: "/page-2-2" },
],
},
{
name: "Page 3",
link: "/page-3",
},
{
name: "Page 4",
subpages: [
{ name: "Page (4-1)", link: "/page-4-1" },
{ name: "Page (4-2)", link: "/page-4-2" },
{ name: "Page (4-3)", link: "/page-4-3" },
],
},
];
// Find out function
// Level must 0 at beginning
function findout(pages, search, level = 0) {
for (const page of pages) {
if (page.link === search || page.path === search) {
if (level === 0) {
return page.name;
}
return true;
}
if (Array.isArray(page.subpages)) {
if (findout(page.subpages, search, level + 1)) {
if (level === 0) {
return page.name;
}
return true;
}
}
}
return false;
}
console.log(findout(links, "/page-4-3"))
The second question I suggest this
const links = [
{
name: "Page 1",
path: "/page-1",
},
{
name: "Page-2",
subpages: [
{ name: "Page (2-1)", path: "/page-2-1" },
{ name: "Page (2-2)", path: "/page-2-2" },
],
},
{
name: "Page 3",
link: "/page-3",
},
{
name: "Page 4",
subpages: [
{ name: "Page (4-1)", link: "/page-4-1" },
{ name: "Page (4-2)", link: "/page-4-2" },
{ name: "Page (4-3)", link: "/page-4-3" },
],
},
];
function findout2(pages, search, result = []) {
for (const page of pages) {
if (typeof page.link === "string" && search.includes(page.link)) {
result.push({ name: page.name, link: page.link });
} else if (typeof page.path === "string" && search.includes(page.path)) {
result.push({ name: page.name, path: page.path });
}
if (Array.isArray(page.subpages)){
findout2(page.subpages, search, result)
}
}
return result
}
console.log(findout2(links, ['/page-1', '/page-2-1', '/page-4-2']))
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'm doing a project with VueJS, Lodash and Babel, and my problem is that i need to populate a sidebar in my app with routes from a routes.js file. Problem is i don't really know how i can retrieve the data i need.
export default [
{
path: "/admin/login",
name: "admin.login",
component: Login
},
{
path: "/admin",
component: MasterLayout,
meta: { auth: true },
children: [
{
path: "/admin/dashboard",
alias: "/",
menu: { text: "", icon: ""},
name: "admin.dashboard",
component: DashboardIndex
}
]
},
{
path: '/403',
name: 'error.forbidden',
component: ErrorForbidden
},
{
path: "*",
name: 'error.notfound',
component: ErrorPageNotFound
}
];
That is my routes file, i basically need to iterate over each route, check if it has children or a menu property, if it has a menu it gets added to my list of sidebar items, and it's children get added as well with their own menu properties being withdrawn
In the end i'd like to get something like the following
sidebarItems: [
{
name: 'Dashboard',
icon: 'dashboard',
name: 'admin.dashboard'
},
{
name: 'OtherRoute',
icon: 'other-route',
name: 'admin.other-route',
children: [
{
name: 'SubRoute',
icon: 'sub-route',
name: 'admin.sub'
}
]
}
]
This should only account for the routes that contain a menu property.
You basically need iterate recursive over the array, so please try this:
function iterateArrayRoutes(routeArray) {
if(routeArray instanceof Array) {
var routeFormatted = routeArray.reduce(function(last, route){
if (route.hasOwnProperty("menu")) {
var item = {
name: route.name,
icon: route.menu.icon
};
if(route.hasOwnProperty("children") && route.children.length > 0) {
item.children = iterateArrayRoutes(route.children);
}
last.push(item);
}
return last;
}, []);
return routeFormatted;
}
};
Here you have a Demo https://jsfiddle.net/vm1hrwLL/
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."