I've been researching but couldn't find a clear answer. As far as I know using global variables in nextjs isn't considered best practice but what is wrong with assigning locale, regions, navigation etc as global variable instead of prop drilling it to every component?
pages/_app.jsx
global.locale = useRouter().locale
global.regions = regions
global.navigation = navigation
...
useRouter is a hook which would trigger a rerender in case the locale changes. When you assign it to a global variable changes to the locale will not have an effect on what React is rendering.
Usually, the locale doesn't change but in theory a link can tell the router to switch the locale without reloading the page from the server.
Instead of prop drilling (pretty cumbersome) you can call the hook in every component where the locale is needed (like links). Assigning the variable to an observable MobX store would be similar to having a global variable and not require prop drilling or repeated use of the same hook. There is also a HOC called withRouter.
Related
I've made a custom resource and I want to load it as a default in an export variable so I've tried this:
extends Node2D
export(Resource) var custom_res=CUSTOM_RESOURCE.new()
and my custom resource script as such:
extends Resource
class_name CUSTOM_RESOURCE
export var data=10
but for some reason it doesn't seem to show up within the editor:
am I doing something wrong?
shouldn't the editor display the custom resource as default whenever the scene is instanced like this?:
Running the initialization in the editor
That initialization is not running in the editor, only when the game starts.
You know the solution is tool:
tool
extends Node2D
export(Resource) var custom_res=CUSTOM_RESOURCE.new()
And all that comes with it. For people finding this form search, be aware of Engine.editor_hint.
Setting the default value
Turns out the reason we need the initializer to run is because what we are setting (CUSTOM_RESOURCE.new()) is not constant.
We can confirm that with a simple constant, for example:
export var x := 5
In that case the initializer didn't run in the editor per-se. Instead Godot set the constant was set as the default value when it parsed the script. And that is what we see in the Inspector.
So we want a constant value of our custom resource. Well, preload is a constant expression (preload is a keyword not a method). And yes, it is resolved while parsing. And yes, Godot will set it as default value, despite it not being a primitive type. Thus we can preload a resource file and use that, for example:
export var custom_res:Resource = preload("res://new_resource.tres")
Which, of course, requires that we have resource file to preload. We can create it from the context menu on the FileSystem by selecting "New Resource…", then picking our custom resource class, and a file name to save it.
Notice this differs from running the initializer in the editor in that:
It does not require tool and all that comes with that.
With tool, the default value remains (null). So you will see the arrow to reset the value in the editor, and clicking it erases the value of the property.
Your custom resource object will be the default value. So you won't see the arrow to reset the value right away. And if you modify it, resetting it the value gives you your resource object back.
Gotcha: Everywhere you preload the same resource file, you get the same resource object. Modifying it will modify it everywhere. Even across different scenes.
Just wondering if styled components are memoized or whether I can/need to do this independently? Specifically, are the props that are passed into the template literal memoized, such that the styled component is only re-rendered if the value of the props change?
If it needs to be done independently, how do you do this?
I checked the source code and it seems that it hashes the resulting CSS and only updates the page style when the hash is not already present. This should prevent changes to the DOM when the props do not change.
The component itself is not memorized. You could wrap with with React.memo() to achieve that. But you might run into issues when the theme changes.
I am running Xpages in XPiNC.
My usual pattern for an Xpages app is to have a xpHome.xsp page that is set to be the first page that is opened. In this I page I set any scope variables that are at the application level, then head to the "real" first page.
Now I have run into a problem. My current database will send out emails when a status changes, and this will include a doc link to the document, which points to the correct Xpage to open. However, because the user is not going through the home page, then my applicationScope vars are being set.
I thought I could fix this by setting a semaphore in the initApp function - the last thing it would do is to place a "Y" in an applicationScope.semaphore field. So when I open my Xpage the first thing it does is check for that, and if it is null, then I call the initApp function.
For some reason this is not working. But even so I would like to find the equivalent of the old database script "Initialize" event. Something I can call whenever the db is opened for the first time.
How do others handle this problem?
Create a managed Java bean "app" which
works on application scope
sets all application parameters
offers all application parameters
Access the bean with app.xxx in EL or Javascript or call methods directly like app.getXxx() or app.doWhatEverYouWant() in JavaScript.
The bean "app" gets initalized automatically when one of the methods gets called first time.
You can find an example here for start or google for "XPages managed beans" for more Information.
Yes, you have to switch your current code partly to Java but it should be worth it in the long run.
If you want to or have to stay with JavaScript then initialize your application scope variables in a custom control which is included in every XPage like layout.xsp in beforePageLoad event.
Use an additional variable applicationScope.initialized. Check if applicationScope variables aren't initialized yet in JavaScript with
if (!applicationScope.initialized) {
... initialize your applicationScope variables ...
applicationScope.initialized = "yes";
}
I'm having a strange issue with Yii and a theme. I set it in config/main.php like:
'theme'=>'themeName',
as usual. But when I try to render a view, it is rendered as is, without any layout, as if I called:
$this->renderPartial
I double check that I don't call for renderPartial, the themes seem to be equal to all the others theme I've done. What can be this issue about?
Thank's for any help, I'm going out of mind on this...
Here is the structure and syntax that you should have to check
-yiiroot
-!-!protected
-!-!-!controllers
-!-!-!-!TestController.php
-!-!themes
-!-!-!themeName (it was the one that you have set on config file)
-!-!-!-!views
-!-!-!-!-!layouts
-!-!-!-!-!-!main.php // It would be default what if public $layout has not been overwriten or the layout file which has been set was not found
-!-!-!-!-!test
-!-!-!-!-!-!viewName.php
On controller TestController
public $layout is main as default or is overwritten there
in actionIndex you set $this->render('viewName');
If you rendered your page by method renderPartial() directly in controller, you would not get the layout template for sure
render() is commonly used to render a view that corresponds to what a
user sees as a "page" in your application. It first renders the view
you have specified and then renders the layout for the current
controller action (if applicable), placing the result of the first
render into the layout. It then performs output processing (which at
this time means automatically inserting any necessary tags
and updating dynamic content) and finally outputs the result.
renderPartial() is commonly used to render a "piece" of a page. The
main difference from render() is that this method does not place the
results of the render in a layout. By default it also does not perform
output processing, but you can override this behavior using the
$processOutput parameter.
renderFile() is a low-level method that does the grunt work of
rendering: it extracts the data variables in the current scope and
then runs the view code. The other two methods internally call this
one, but you should practically never need to call it yourself. If you
do, keep in mind that you need to pass in a file path (not a view
path).
Reference: Yii difference between rendering functions
On a page I have some fields that I want to be "readonly" (in my meaning they can't be accessed but they will store values, read earlier question in this matter if issues...).
I use a client JS setting these attributes on page load:
$(".readonly").attr('readonly', true);
If I have a partial update on any of these fields the attribute is lost and the field is accessible.
What is the best practice to overcome this and make it work?
Every partial refresh has a oncomplete method bound to it. What you could do is add code to the oncomplete method so the item is being set readonly again. Another, better, approach would be not to change the attribute clientside but to have hidden fields which are used to store the data.
When you have an event bound to for instance an Link control you can change the oncomplete code by clicking in your source pane on the event tag. When you browse the events section in the properties pane you will see the onComplete, onError, onStart properties. You can add your own clientside script in these properties.
Before trying to overcome the "problem" You shoud try to understand what exactly partial refresh do and where the state of application is kept.
Unfortunately partial refresh is replacing current html content (or rather part of it) with a newly created one and only form fields that has backing controls will keep state.
I suggest You should try setting readonly property on controls which You would like to make readonly (if there is some logic here You can always use ssjs).
Optionally You can try to preserve the state on the client side by using csjs global variables but this is rather hard to manage.
And one more thing - try to use the technology to solve the problem(xpages) and try not to hack Your way through with use of stuff that You accidentally know (jquery).
I would agree with jjtbsomhorst on using onComplete event. But another alternative could be setting the readonly property via code like this:
var textField:com.ibm.xsp.component.xp.XspInputText = getComponent("inputText1");
var readOnlyAttr:com.ibm.xsp.complex.Attr = new com.ibm.xsp.complex.Attr("readonly", "readonly");
var list:java.util.ArrayList = new java.util.ArrayList();
list.add(readOnlyAttr);
textField.setAttrs(list);
You could call this on the afterPageLoad event of the XPage. But I really don't know whether this would be the best way to about!