We develop an Ember based framework for internal use of various groups within our organization. Along with this, we maintain a demo page, which displays all the components we've developed along with documentation on how to use the components. I need to modify one of the component demo pages, to allow the user to custom build the component. For example, the component has two properties showCheckboxes and showRadioButtons. By default, showCheckboxes is true, and the component, of course, displays checkboxes. I want to add a select so the user can choose between radio buttons and checkboxes. Everything is wired up correctly and the routes action gets called, but, if I select radioButtons, the component does not refresh and display readio buttons. I've set breakpoints and I see that the route is not called, so the new properties are not read. How can I force Ember to rebuild the component from scratch? I've tried this.refresh() in the route, I've tried setting the model to the new model with the changes, but the component does not redraw with the new properties. I've also tried transitionTo. But if I don't pass a model, nothing happens. But if I pass in the new route, I get this error:
Error: More context objects were passed than there are dynamic segments for the route
I hope this was clear enough for someone to provide some guidance.
Thanks
Related
I am working on a React Native project, and I am currently focused in the Chatroom aspect. Due to user roles, this component is embedded in another component for 2 of the 3 user types, but navigated to (not embedded in anything other than App.js) for the other type.
This means sometimes the app uses the props it was supplied with, and other times it uses the props.route.params?.item syntax to extract information. As is such its difficult to maneuver with useEffects to make sure it works on both sides.
The issue I am facing is with the embedded version of this component. It takes three props, the chatroom, and two booleans that are unrelated to this. The chatroom can change as a GUARDIAN user can see their CHILD user's messages, but they cannot text in them (those are the other two boolean values). From the parent component, users can toggle whether they are the Guardian accessing their own chat, or if they want to view their children' chats. While the all three values change properly (I console.log'd this in the parent component to confirm) the chatroom does not change inside of the embedded component.
I will show you what I mean...
// PARENT COMPONENT //
function renderMessageThread(chat){
console.log("\n\n\n", chat[0].messages.length, "LANDING")
console.log(msgUser.id, isThisChatMine())
return <MessageThread hardCodedChat={chat} hardCoderUserId={msgUser.id} isItMe={isThisChatMine()} />
}
The console.logs show the proper values. Inside the MessageThread component, both hardCoderUserId and isItMe are correct values, even when isItMe changes values. hardCodedChat, however, never has its value changed from the first time it is created. Does anyone have any ideas on how to have this changes as well?
I've got a complex component which does all its rendering in a render function. There are multiple parts to this, and different bits of the view get rendered - one of these things is a filter bar, showing the filters that have been applied.
What I'm noticing happening, is if I apply a filter which in turn presents this bar, it causes everything else to be fully re-rendered. This is causing a number of other issues and I need to try and stop it from happening.
I've never come across this issue when using normal templates as Vue seems to handle these very intelligently, but I have no idea how to tackle this. The only thing I can think of is setting a key on each thing I don't want re-rendered but not sure if this will a) solve the problem, and b) be possible for the content that is passed in through a slot
Has anyone else faced this issue, and if so how can it be solved?
I had a similar issue when using vuetify text inputs in a complex component which was causing the app to slow down drastically.
In my search I found this link which was specific to vuetify:
high performance impact when using a lot of v-text-field
then found out that this is actually a vue thing from this GitHub issue:
Component with slot re-renders even if the slot or component data has not changed
and there is plan to improve this in it is tracked here (vue 3 should resolve this issue):
Update slot content without re-rendering rest of component
so after reading through all these I found some workarounds that helped me a lot to boost the performance of my app, I hope these will help you as well:
divide that complex component into smaller ones specially when there is some bit of code that changes data that bounds to template causing re-rendering (put them in their own component)
I moved all data layer control to the vuex store, instead of using v-model every where and passing data as events and props, all the data is updating in the store through an action and read from the store through a getter. (from data I mean somethings that is being looped in the template in a v-for, API results, and so on... all of them is being set, updated and read through the store. my components still have the data object but only for the things related to the style and template control like a boolean to control a modal or an imported icon which is used in the template and alikes)
lastly I wrote a function called lazyCaller which its job is to update the values in the store with a delay (when immediate data update isn't necessary) to avoid rapid updates comping from something like a text input (with out this every key stroke trigger the value update action)
I have one ReactJS App which I reduced to the minimum as possible on the diagram below:
Side note: On this App I use Redux to manage state changes.
This App contains:
Component: UploadScreen with an image holder and a button. When that button is clicked, the user gets displayed a Popup Window which let him to pick an image from his device file system. Then that image is displayed on the image holder.
Component: AuxWidget which is a totally different component (needs to be separate) which also contains a button that when it is clicked it should popup the Select File window. I was thinking in something like triggering the click event of the first button.
Any idea on how to achieve that?
First I though about using Redux but I think that's not a too good idea because even though you can send messages with it from one component to another, that causes a render update and I don't want that.
Also, I was thinking on using jQuery but that's not the best approach when it comes to ReactJS.
Also, I thought about using the attribute: ref="foo" to get a reference to the other component but I think that's normally done when you want the interaction to be between parent and child components.
Also, I was thinking about EventEmmitter but I don't know if that's the best approach on this case (I'm using Redux to manage the state changes between components).
One of the best ways I can suggest using RxJS, you can create a Subject and pass it to your components. In one component you will need to subscribe to it and whenever you will call next on your subject from the second component, the other will be notified, so you can trigger open popup. You can even create your own implementation for this in case you don't want to add new library to your project.
The upload window could be triggered when a certain state in the app changes. The relevant state on the app could be changed from different places, like from AuxWidget and UploadScreen. That way they are not coupled with the upload window. They merely call a function that is passed to them and that function changes the state on the app and it will display the window.
If you have a shared component between two unrelated component I think it is best to lift that common component and let its state sit on a higher level.
If I understand things correctly, your primary concern is code-reuse as opposed to wanting to call a sibling method. Basically, you want a SelectFilePopup component that can be re-used (open/closed) cleanly. I think React Portals could be a good solution for this. I found a good example (https://github.com/Assortment/react-modal-component/blob/master/src/components/Modal.js) of how a Modal can be isolated into a component and be called anywhere in the codebase.
The usage of the Modal looks like this (copied and slightly modified from App.js in the github project above)
import Modal from './components/Modal';
<Modal><div>Click me to open Modal</div></Modal>
And the Modal component implementation (simplified)
render() {
return (
<Fragment>
<ModalTrigger
onOpen={this.onOpen}
/>
{isOpen &&
<ModalContent/>
}
</Fragment>
)
}
By default the Modal component shows a trigger (i.e button) when isOpen state is false. Once clicked, and isOpen switches to true, the ModalContent (i.e can be the FilePickerPopup) is dynamically created and attached to document body. You can check out the source code for more details. I think its a very clean solution to modals. So in your case, your code could end up looking something like this
UploadScreen.js
import FileSelectPopup from './components/FileSelectPopup';
<FileSelectPopup>{Upload Image}</FileSelectPopup>
AuxWidget.js
import FileSelectPopup from './components/FileSelectPopup';
<FileSelectPopup>{Upload Image or some other text}</FileSelectPopup>
So basically, AuxWidget doesn't even need to know about where the FileSelectPopup is located at. It's an independent component that can be called anywhere. The caveat is that the Modal implementation in the project I linked to is not a singleton (although it can be modified to be one). So if AuxWidget and UploadScreen are visible to the user at the same time, clicking both Upload Image buttons will create two instances of the Popup.
I would define the function in the parent component and pass it to both children as props
I have a backbone.js app, whose views have multiple states, which differ substantially from each other ("View","Edit", etc). There are at least 2 different templates for every view. This is OK. My problem is with the JS view managing code.
I rely on an initalize-thin-render-thick approach (which, I think is pretty bad), where the render method is where 80%-90% of the logic occurs. When I want to change the state, I simply call the render method with a specific parameter ("view","edit"). On the basis of that, the view decides what to show and what not, to which events to bind, etc.
I think this is bad, because, on one side it puts bottlenecks on the rendering process, on another, it is not proper state machine, which means that I am not carrying about possible callbacks that might have been bound previously. When I receive the view, I simply clean the view and that's it.
I also observed, that I am not using the delegated event system, provided by backbone, which I think is another minus, because I think, it is very well implemented (BTW, does it make sure to unbind callbacks, when a certain DOM element is removed?)
I think I need some serious refactoring. Please, help with some advice, as to what the best approach for a multi-state Backone view would be.
What I tend to do for these cases is to make a toplevel view that manages a subview for each individual state (index, show, edit, etc.). When a user action is invoked, e.g. "edit this user", "delete this user", "save my changes", the active state view signals the router (directly, or through a hyperlink), and the router will tell the toplevel view to update its state.
Continuing the user editor example, let's say that I have a top level view called UserEditorView. It renders a basic container for the user editor (title bars, etc.) and then, by default, instantiates and renders Users.IndexView inside that container.
Users.IndexView renders the list of users. Next to each user is an edit icon, which is a link to "#users/555/edit". So, when the user clicks it, that event goes to the router, which tells UserEditorView, "hey, I want to edit user #555". And then UserEditorView will remove the IndexView (by calling its .remove() method), instantiate Users.EditView for the appropriate user model, and put the EditView into the container.
When the user is done editing the user, she clicks on "Save", and then EditView saves the model. Now we need to get back to the IndexView. EditView calls window.router.navigate('users', { trigger: true }), so the URL gets updated and the router gets invoked. The router then calls .showIndex() on the UserEditorView, and the UserEditorView does the swap back to IndexView from EditView.
On a simple way to manage unloading of events, I've found this article on zombie views quite useful.
Basically, I don't have a toplevel view, but I render all the views using a view handler that takes care of the views for a given container.
To make your renderer thinner, I would recommend using routes. They are easy to setup, and you can have different views for each route. Or, what I'm used to do is just to have different templates. Using a general Backbone.View overwrite:
Backbone.View = Backbone.View.extend({
initialize: function(attrs) {
attrs = attrs || {}
if(!_.isUndefined(attrs.template)) {
this.template = attrs.template;
}
}
});
I've noticed that I reuse views in two ways:
1. edit views differ only in the underlying model and template, but not the associated logic (clicking the submit validates and saves the model)
2. the same view can be reused in several places with different templates (like a list of users as a ranking or you accounts)
With the above extension, I can pass {template: '/my/current/template/} to the view, and it will be rendered as I want. Together with routes, I finally got a flexible, easy to understand and thin setup.
I found on this page a great example of https://github.com/emberjs/ember.js/issues/11043 how to inherits from a component. Here is the example: http://emberjs.jsbin.com/rwjblue/443/edit?html,css,js,output
I played a bit with and especially with actions and come to this question:
How can I set the context of the component?
Consider the following examples:
http://emberjs.jsbin.com/cofobanoca/edit?html,css,js,output
and a derivate of it
http://emberjs.jsbin.com/gipawemipe/1/edit?html,css,js,output
They are pretty much the same except that in the second link, the component is dynamically create inside an action.
My question is, why is {{this}} in the second example a "generated application controller" and not a "App.XBarComponent"?
EDIT:
Maybe I was not clear.
What I want to achieve is to render a modal which contains inputs fields. This should be rendered inside the application template (using outlet) as a popup over the whole page. The Modal is built with two components just like foo and bar. BaseModal (which is Foo) and LoginModalContent (which is Bar) are better names.
On click on OK (which is defined in BaseModal), I want to call the OK action of LoginModalContent to be able to get the values of the forms (defined in LoginModalContent) using e.g. this.get('username').
They are pretty much the same except that in the second link, the
component is dynamically create inside an action.
There you're not creating a component, just rendering a view, and if you don't specify a controller for a view Ember creates one for you, that's why {{this}} is "generated application controller" in the second example.
That also explains why the action handler of the XBarComponent doesn't work in the second example, since the view is missing the component controller.
If you want to programatically insert components the component helper is your best bet, it renders components by its name while letting Ember handle the view/controller/subcomponents management.