How to organize your static text in a single page app? - node.js

Imagine you have a single page applications with lot of static text in a reactjs app.
for example :
import Block from './components/block';
const arr = [
{
name: 'block1',
text: '<p>Lot of static text 1</p>'
},
{
name: 'block2',
text: '<p>Lot of static text 2</p>'
},
{
name: 'block3',
text: '<p>Lot of static text 3</p>'
},
{
name: 'block4',
text: '<p>Lot of static text 4</p>'
}
];
...
render() {
return (
arr.map((a, i) => {
return (
<Block key={i} text={a.text} />
);
})
);
}
...
So the "Lot of static text" are very bigger.
How do you organize this text in all components ? Do you create a model.js file in the repo components or something ? there are a best practice for this ?
Thanks :)

You can create one JSON file for the same and fetch each detail using http.
You can store you data in some Global Service and use whenever needed by importing that file.
Also you can create model.js file for the same.
But i would like to suggest first one, if you have to use for limited time else second option is good.

ES7 suggests to store static data and methods inside static classes (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static). This is the current best practice.

Related

How to access custom cms element config values in Shopware 6?

FYI: Products is my cms element name.
As shown in shopware 6 guides, I have created a file
DataResolver/ProductsCmsElementResolver.php
which has an enrich method which helps to extend data. In there I try to access the configs of my custom cms element with:
$config = $slot->getFieldConfig();
$productListType = $config->get('products')->getValue();
That, however always returns the default value that was set during the registration of the element:
Shopware.Service('cmsService').registerCmsElement({
name: 'products',
label: 'das.elements.customProductsElement.label',
component: 'sw-cms-el-products',
configComponent: 'sw-cms-el-config-products',
previewComponent: 'sw-cms-el-preview-products',
defaultConfig: {
products: {
source: 'static',
value: ''
}
}
});
I did it exactly as it is shown in the following guides:
https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-cms-element
https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-data-to-cms-elements#create-a-data-resolver
Could anyone share a sample of code where you get the value of config as a variable and not static value?
What I was doing wrong was that I forgot to write the .value in computed methods:
computed: {
products() {
return this.element.config.products.value;
}
},
However I also found such function call in shopware source codes which was not mentioned in the docs:
methods: {
createdComponent() {
this.initElementConfig('youtube-video');
this.initElementData('youtube-video'); // this line was not present in docs
}
}
I assume you haven't done any further handling of the product data in your config component, as you do not mention it.
I suggest having a look at the default cms components like for example shopware/administration/Resources/app/administration/src/module/sw-cms/elements/product-slider/config/index.js where you can see how product data is handled :)

Rendering one of multiple pages with lit-element

The lit-element documentation describes conditional rendering via (condition ? a : b). I was wondering how to use that to render one of multiple pages, f.e. in combination with mwc-tab-bar from Googles material web components.
My current solution is something like this:
render() {
... other stuff ...
${this.selectedPage === 0 ? html`
<div>
...
</div>
` : html``}
${this.selectedPage === 1 ? html`
<div>
...
</div>
` : html``}
... further pages ...
}
I don't like the :html`` part but is that how it's meant to be?
Use more simple code like this.
constructor(){
super();
// don't forget add `prop` and `selectedPage` to `static get properties()`
this.prop = 1;
}
render() {
return this.getPage(this.selectedPage);
}
getPage(num){
switch(num){
default:
case 1:
return html`<div>P${this.prop}<div>`;
case 2:
return html`<div>P2<div>`;
}
}
There are multiple ways of achieving this, your solution is one, but as you mention, it's not the prettiest
One way you could modularize this somewhat is using an object/array and render functions, basically the idea is this:
First, define render functions for each page (this can be on the same file or on different files):
const page0Renderer = (context) => {
return html`<section>${context.someData}</section>`;
};
Then, you could define an object that has a match between the page identifiers and their respective functions, you are using numbers so the sample below uses numbers:
const pageRenderers = {
'0': page0Renderer,
'1': page1Renderer,
'2': page2Renderer,
// etc
};
And in your main render function you could use all these like this:
render() {
return html`
${pageRenderers[`${this.selectedPage}`](this)}
`;
}
This would basically call the render function that matches the selected page and send it a reference to the main web component so that you can access its properties.
Then again, this approach also has its flaws and I wouldn't really recommend it much if you need your child templates to be complex.
In that case, instead of rendering functions you probably would be better off creating other components for each view and that way you could also do some lazy loading and so on.
For that kind of approach, you might want to check out routers like vaadin router which help you both with routing and changing which component gets displayed accordingly

how to add a node import statement to a file with angular schematics?

I want a custom schematic that will create a page in my application. To do this, I want to use the existing core schematics to create a routing module, then create a component in that module to display my page content, and finally wire everything together. It's the "wire everything together" that has me stumped. I can't find clear guidance on the "right" way to to this. Should I:
a) directly modify the existing files that the "module" and "component" schematics created? (I don't know how to do that)
b) use templates to somehow merge the modifications into the files? (I don't know how to do this either)
Below is the index.ts file for my page schematic as of now. What I don't know how to do is commented by "TODO" towards the end.
Please help!
import {
externalSchematic,
Rule,
SchematicContext,
Tree,
chain,
} from '#angular-devkit/schematics';
export function page(options: any): Rule {
const name = options.name;
return chain([
// create module for this page
externalSchematic('#schematics/angular', 'module', {
name: `pages/${name}`,
routing: true
}),
// create simple component to display in this page
externalSchematic('#schematics/angular', 'component', {
name: `pages/${name}/${name}`,
routing: true
}),
// add component to routing module
(tree: Tree, _context: SchematicContext) => {
// TODO 1: import new component into routing module
// e.g. import { MyPageComponent } from "./my-page/my-page.component";
// TODO 2: add component to routes
// const routes: Routes = [{ path: '', pathMatch: 'full', component: MyPageComponent }];
return tree;
},
]);
}

Statically load a QML Component without instantiating it

As I understand it, a QML Component is like a kind of like a class in C++. It contains the definition of a QML object but isn't an instance of it. You can create a Component in these ways:
Creating a .qml file with the component name as its filename.
Define it inline with the Component { } syntax.
However these are actually two different things. The second one is more like a factory because you can do things like:
Component {
id: factory
Rectangle { width: 100; height:100; color: "red }
}
Component.onCompleted: {
var rect1 = factory.createObject(parent);
}
Whereas with the separate file you need to first load it into a factory like this:
var factory = Qt.createComponent("RedRectangle.qml")
var rect1 = factory.createObject(parent);
I'm only concerned with dynamic object creation, so this is not an option:
RedRectangle {
id: rect1
}
My question is: is there a way to create the objects dynamically, without having to create the Component factory dynamically too, and without having to specify the Component inline. I.e. I want the first example, but where the Rectangle is specified in another file.
I want this:
Component {
id: factory
url: "RedRectangle.qml"
}
Component.onCompleted: {
var rect1 = factory.createObject(parent);
}
Sadly that doesn't work. I also tried this:
Component {
id: factory
}
Component.onCompleted: factory.loadUrl("RedRectangle.qml");
But it doesn't work either. Am I being stupid or is this just not supported?
Here is some encapsulation:
Fact.qml (for some reason it doesn't let me name it Factory)
QtObject {
property string url
readonly property Component component : Qt.createComponent(url)
function get() { return component }
function load(url) { return Qt.createComponent(url) }
}
usage:
Fact {
id: f
url: "RedRect.qml"
}
StackView {
id: stack
}
Component.onCompleted: {
stack.push(f.component) // redrect
f.url = "BlueRect.qml"
stack.push(f.get()) // bluerect, redundant but shorter
stack.push(f.load("GreenRect.qml")) // greenrect, f.component is still bluerect
}
It will only load the component when its component property is referenced and you can change the url to load other components with the same Fact instance. Also the auxiliary load() method, which returns a component without actually changing the one potentially cached.
Actually the answer is not too bad, though I still think Component should support specifying a url directly.
Here is my solution:
property var factory: Qt.createComponent("RedRectangle.qml")

Can I add attributes to a Backbone View?

I have been working with backbone for a while and I am now using a number of views. In some of my views I sometimes add custom attributes like:
var DataGrid = Backbone.View.extend({
className:"datagrid",
lookup: {
header: "", //Header wrapper row element
headers: [], //Views in header
body: "", //Body wrapper row element
rows: [] //Views in body
},
events: {
...
},
initialize: function() {
...
},
render: function() {
...
}
});
As you can see I have "lookup" as an extra attribute to the Object. I use DataGrid in a number of my views and I am experiencing a very strange behaviour. When I switch between views that use DataGrid, "lookup" would still be populated with the old data. I use "new" when creating a new DataGrid but I still find old data. Am I missing something?
EDIT: Following #rabs reply. I did a search on static variables in Backbone and found this: Simplify using static class properties in Backbone.js with Coffeescript
I know an answer has been accepted on this (a while ago), but as I came across this question while working on a backbone project recently, I thought it would be worth mentioning that you can define attributes as a function also. This is especially useful for views that need to have attributes set to values in their current models.
By defining attributes as a function you can do something like
var myObject = Backbone.View.extends({
attributes: function() {
if(this.model) {
return {
value: this.model.get('age')
}
}
return {}
}
});
Hope that helps someone
Declaring variables in this way the scope of the variable is to the class not the instance, similar to s static or class variable.
So yeah the lookup object will shared between your different instances.
You could pass the lookup object in to your instance when you create it that way it will behave as an instance variable.

Resources