I’m discovering React and I think there’s something I don’t understand correctly. Where am I supposed to put the code which computes things before displaying them, what would be the Model in a traditional MVC? Let’s say my app deals with fruits, and I want to display a list of them. So I get the list from an API (something like [{type: banana, boughtDate: 2021-01-03}, {type: apple, boughtDate: 2021-01-02}], give it to a FruitsList component, which loops over and generate FruitRow components. Now, I want to display every rows which are a banana in yellow. I can add a style="color: yellow" in my row component with a condition on the fruit type. But what if I want to have this color in every places where a banana is displayed in my app? That would duplicate this kind of if in every components. What is the React solution to this?
I could have an “utils” file with a function which takes a fruit and return the color, I guess, but that sounds like a very 2005 way of coding. Where I’m confused is that, in Java or other object languages where I come from, I would have a getColor() method on the Fruit class, and the Banana subclass would override it to return yellow. Or at the very least I would have the if (type === "banana") only once, in the getColor method of Fruit class. Can I (and should I) try to recreate that model in React with Javascript classes? So my ¨logical" code is only in one place, and then I could have generic component like Row which would take content and color as props, instead of a Fruit? If yes, where should I put this code?
Edit: Searching on the web, the official React doc links to this presentation by Pete Hunt from Facebook in 2013, where he says: "only put display logic in your components, I'm not advocating putting all your model validation code and fetching and data access in components, you might want to put them in third-party libraries that have some sort of bridges to your components, but only put logic that makes sense in your components"
So I think this is what I'm talking about, are there good practices about those "bridges", where do you put this logic?
Do this where you want to render anything that happens to have type: banana
<BananaType>
<WhateverYouWantToPutHere/>
</BananaType
And define BananaType like this:
const BananaType = props => <div style="color: yellow">{props.children}</div>
You can add logic to the BananaType component (e.g. fetch a thumbnail from an API) as well. Just do something like this:
const BananaType = props => {
const fetched_stuff = someHandyFunctionForFetchingStuff();
return <div><div>{fetched_stuff}</div>{props.children}</div>
}
If you only want to do some logic, and don't want to change the DOM at all, do this:
const BananaType = props => {
// Do whatever stuff you want to do here
return props.children;
}
I could have an “utils” file with a function which takes a fruit and return the color, I guess, but that sounds like a very 2005 way of coding.
Absolutely not at all! One of the things that makes react so strong is that it plays well with existing accepted practices and gives you options. Lets look at the issue you described and see what solutions we might be able to come up with.
Now, I want to display every rows which are a banana in yellow. I can add a style="color: yellow" in my row component with a condition on the fruit type.
So an important distinction to make here is, do you only want to style the row, or do you want to style "bananna" everywhere?
But what if I want to have this color in every places where a banana is displayed in my app? That would duplicate this kind of if in every components.
OPTION 1
In that case you COULD create a <Bananna /> component (and for each other fruit) and render that, which means you only need to style that one component and changing it in one place will affect all others.
OPTION 2
Use the method you descibed and just have it in a helper/utils file. I've been working on react applications since mid 2016 and I STILL find use for having separate files with re-usable logic in them.
OPTION 3
Your second option could be to use css module for this approach, using css modules would allow you to do something like css[bananna] in your component and which would apply the styling and prevent the need for you to have a switch statement.
Related
Lets imagine, that we have some catalog, let it be the goods catalog. You have top level categories and many subcategories for them and so on deeper. The whole menu can be of any deep.Of course I don't want to hardcode this catalog, I want to load its structure from a remote server (REST API for instance), so that I could change it any time wothout posting changes to apps
I am using React-navigation (if it makes any sense). How it is usually done?(1) Should I somehow create one page and pass there some parameters, or (2) should I create many distinct pages.In the first case (1) I can't even imagine, how can I pass new parameters to the same page again and again in such a way that each time there would be a new title in header of this page and a new submenu structure to be displayed.The second way (2) seems rather complex to me and is not the best idea... I suppose.What are best practices?enter image description here
I'm using HP UFT for functional tests.
Because of dynamic id definition of ExtJS, I can't use UFT Recording feature.
I've tried many ways for assigning dynamic IDs to staticly.
I tried to change id: function() in ext-all-debug.js file.
I tried to change Components getId() function in ext-all-debug.js file.
I tried override components with afterRender method to change ids aswell.
Sometimes I achieved to change id's using component's properties (text, fieldLabel, overflowText, etc.), but for some components I couldn't achieve to assign ID's since the components properties seem empty.
Above, I listed my actions to assign static ID. So, I want to know your opinions about my actions and if you found them incorrect or not sufficient, could you offer me new approaches for using HP UFT recording feature with ExtJS6.
You can't change the dynamic id of the dom elements which represents ExtJS components. That's really bad thing and I think you would break the whole app.
The easiest way to test ExtJS app is to use already created frameworks/tools like:
Siesta by Bryntum
Sencha Test by Sencha
The Siesta is free. It has some pro features which requires the license. But you can use it for free.
If you still insists on doing it your way. You need to dynamically get the IDs of the dom elements created by ExtJS components. Basically write your own API.
You need to execute the ExtJS JS code, which will return you the ID of the component. So you need to get the ExtJS component and call getId() function on it to get the dom id.
Here is the example code:
>Ext.ComponentQuery.query('checkbox')[0].getId()
"checkbox-1047"
You will definetely need: http://docs.sencha.com/extjs/6.5.3/modern/Ext.ComponentQuery.html#method-query
And keep in mind that the query can be pretty advanced and you can use all the configs which are set on the ExtJS elements such as name, xtype, etc
You can find some other info in my other anwser https://stackoverflow.com/a/41718879/1768843
Sorry if my question is silly but I'm new to DNN/2sxc, I've spent the whole day trying to figure this with no success..
I have two instances of the same app, one in the home page and the other on its own page, each one must have its own view template (I use Razor).
My problem is I cannot figure a way to make the two apps read the same data, so every add/edit/remove/re-sort in one of them will be reflected to the other, currently each app has its own data and therefore they are unusable in my case.
I've tried to use a 'EntityTypeFilter' inside a 'Data Query' and use it in both views (as in the News-Simple demo video), it worked and gave me all the items in the two views, but another two problems come with this solution:
1- now I'm unable to use the toolbar to (add/remove/reorder,.. etc) any of the items , as you can see in this image, which is a show-stopper for me,
note: this is the toolbar I use:
#foreach(var item in AsDynamic(Data["Default"]))
{
...
#Edit.Toolbar(target: item, actions: "new,edit,replace,remove,moveup,movedown,instance-list")
2- the 'Content Demo Item' is also visible in the list, but it is not that important since I can delete it and use one of the real data items as a demo item.
I appreciate any kind of help.
Thank you.
So the first thing you should know is the difference when using content-items as data (to query, etc.) and when using it as assigned-items (where each module-instance has a subset of items). Here's the blog that should help you understand the difference: http://2sxc.org/en/blog/post/12-differences-when-templating-data-instead-of-content
So when you want the "manually and easily control the exact items displayed, their ordering etc." you want to use the "content-assigned-to-instance" which also gives you the simple add, delete buttons, as these don't really delete anything, but just remove the assignment from the module-instance.
Now your case is a bit special, in that you want to re-use the exact same set in another module-instance. There are a few ways you can do this:
Same View
if it's exactly the same view etc. just duplicate the module using DNN-features (the add-existing-module-to-another page)
different view
if it's a different view (maybe more compact, etc.) you again have multiple options. The first is to mirror / duplicate using the dnn-feature, and just put an if-im-on-this-page-then-show-differently or inject another CSS. That's probably the easiest without any dev-know-how.
The harder, but possibly nicer way, is to actually to use a new template, and tell it to retrieve the items in the way they are configured in the other module - let's say module 1 is the original, module 2 has a different template wanting to access the items of module 1 in exactly the same order as given in 1. They way to do this is simple, but requires a few lines of C# code in Module 2.
You need to create a new ModuleDataSource (https://2sxc.org/en/Docs/Feature/feature/4542) object and tell it that it's from Module 1. If you've never done this, it's basically that your code can create a query just like the visual designer, but you have more control - see the wiki https://github.com/2sic/2sxc/wiki/DotNet-DataSources-All. The Module-Data-Source in the visual-query-designer doesn't allow you to "switch" modules (a advanced setting we may add in the future) but the object has a ModuleId property which you can set before accessing the data, making it "switch" to that Module. here's the Pseudo code in your Module#2 razor...
var otherModData = CreateSource<ModuleDataSource>();
otherModData.ModuleId = 1;
foreach(var itm in AsDynamic(otherModData["Default"])) {
...
}
That should do it :)
i need to create a component dynamically by a button click. My restrictions are:
It's going to has an Id starts with a fixed string like 'myComp_' and followed by a random number
At any time there will be only one component that has an id starts with 'myComp_xxx'
So before creating the component i have to check if there's any created before and remove it... My problem starts here. Ext.getCmp() wants the specific id. But i only have that fixed string : myComp_...
Is there any way to get the component created before???
Thanks in advance and sorry about my English.
For ExtJs 4.X use Ext.ComponentQuery.query('*[id^=myComp_xxx]');
For ExtJs 3.X you can either use the following
var el = Ext.query('*[id^=myComp_xxx]');
var cmp = Ext.getCmp(el.id);
Or (this one i haven't tried personally, but i think it should work) if the component is a child of a component that you can access, then:
var el = parentComp.find("action","btn");
and set a property called action : btn in the button config.
I think what you are looking for is DomQuery.
Ex:
Ext.query("*[id^=myComp_xxx]")
You need to use this: Ext.getCmp(id)
Ext.getCmp("myComp_xxx");
Sounds like you should be using the normal component query stuff - in general it is not a good idea to use id. You can query by xtype and by itemId (which you can assign manually).
The following
Ext.ComponentQuery.query('grid form');
would find all things with xtype grid that have forms inside them somewhere.
Ext.ComponentQuery.query('grid #okButton');
whereas the # here is saying look for grids that have something with itemId 'okButton' in them.
You can nest this to whatever level you need and use other operators to be more specific and as someone else has rightly pointed out you can use up and down on components to do this relative to the current component. Its worth noting that rather than getting an array back with all the results you just get the first one when you use up and down.
See the documentation for more information this.
Also see point 6 on this list of bad practices to avoid for more of the why
Another alternative if you know 'where' your component is going to be created is to use the up()/down() methods.
E.g. if you have a button and want to get the form it's contained within inside a click handler you can do something like this:
function myClickHandler(btn) {
var form = btn.up('form');
//do something with form
}
I have two lists of different PageTypes - NewsItems and PressReleases. They are displayed in one list each, with links to the individual items.
Now I want to include the press release items into the news list and use the style of the news items to display them as news items. They share properties like "Heading" and "BodyText", which are used in the News Template.
I imagine that it won't be that difficult to feed the NewsItems' ListPage with both sets of pages, but I don't understand how I can control the rendering of the item page.
I would like to take the PageData object from a NewsItem OR a PressReleaseItem and display it using the News-Item.aspx template, if it is selected in a NewsList. But EPiServer will always render the PressReleaseItem with the PR-Item.aspx since it's coupled in the PageType settings.
Anyone know how to accomplish this?
EDIT: An effort to clarify:
The important issue is how to know the "list parent" and choose the right template from that. In the ListPage I can apply different looks on the PR and News items respectively using tompipes answer, but when selecting to see an individual item EPi will render the PR-Item-1 the same way regardless of their "list parent". That's the problem.
I'm not following exactly what you are attempting here. But I think I get the gist of it.
Why not use one aspx template for both page types, but in the code behind switch off sections using the visible attribute.
If you are using PageTypeBuilder you could use the "is" keyword:
somePlaceHolder.Visible = CurrentPage is NewsItemList;
If you're not using PTB, you could use something like:
somePlaceholder.Visble = CurrentPage.PageTypeID == 10;
or
somePlaceholder.Visble = CurrentPage.PageTypeName == "NewsItemList";
I'll point out now I'm not a fan of hardcoding anything, so I would place the template name, or ID into a config file, or a property on the start/root page to avoid hardcoding them.
Let me know if this will help, or if I have misunderstood please try elaborate on your issue.
Depending on how much the templates share you could go with user controls, placeholders or even different masterpages to switch view in a suitable way.
To know when to switch you could use a querystring parameter, session variable or the nicest looking way would probably be to lookup and get the list's PageData object by the HTTP referrer. If it's empty you will get press release rendering as the worst case.
I tried lots of solutions, including the adding of querystring to the PR items in the list links, the getting of referring url in the item template and different types of event hooking for automatic publishing of news items from a PR item (although I only looked at the code samples for that one), and finally came to the conclusion that they all had something that told me not to go that way. (Making the code too complex, or the markup logic too hard to understand and so forth)
I ended up using Fetch data from another EPiServer page, and creating a "shortcut pagetype" in which I let my editors pick which PR item should be used as base for a news item.
This shortcut pagetype is called "PR-as-news-itemPage" and it is rendered with the same aspx as ordinary news items: News-Item.aspx. Having no properties of its own, it will take all relevant data from the PR item selected with "Fetch..."
To render PR items with all its properties I created an ordinary new pagetype called PR-Item.aspx. This renders the "Attribute 2" property, which is only rendered by PR-item.aspx, and not by News-Item.aspx.
(I could have gone even simpler, by letting the editors use the old News-Item page type and use the "Fetch..." property there, but I have some mandatory properties in that page type which I didn't want to make optional for this sake.)