Nested Queryrenders cause parent renderer to rerender with data returned from inner renderer - relayjs

Say i have a parent component (called Wrapper) that is a QueryRenderer that just fetches:
query productQuery {
product {
id
name
}
}
and then i have a QueryRenderer (that renders a component called Inner) that renders the following query:
query productInnerQuery {
product {
id
}
}
what happens is that inside the outer component Wrapper gets subscribed to updates on product, causing it to rerenders with the productInnerQuery (name is undefined) when the page loads since that component loads on mount. what can i do so that this doesnt happen and that the the outer queryrenderer doesn't get affected by the inner one?

Please see: https://github.com/facebook/relay/issues/1843#issuecomment-378299074
Essentially:
I recommend avoiding QueryRenderer inside QueryRenderer, the top one will rerender the below one in the tree causing another fetch

Related

SAPui5 create entry with child entries

I want to create an entry and its child from the from ui5 so I used the approach of create entry the problem is I want the user to be able to update values of the child nodes so I did the following
var oParentContext = this._oODataModel.createEntry("/Parent",
{ changeId: "edit", properties: {object}, success: this._fnEntityCreated.bind(this), error: this._fnEntityCreationFailed.bind(this) });
for (var i = 0; i < childArray.length; i++) {
var child = childArray[i];
aChildCtx = this._oODataModel.createEntry("/child", {
changeId: "edit",
properties: child,
context: oParentContext
});
aChildEntries.push(aChildCtx.getPath().substring(1));
}
this.getView().setBindingContext(oParentContext);
// I attached also the relation to the front end
this.getView().getModel().setProperty("ToChild", aChildEntries, oParentContext);
In the view I did the binding to the relation ToChild to the table for the user to enter his values.
The display of the parent and child works however I am facing a problem that the view is issuing a get request to Odata with the temporary ID/ToChild. I couldn't find any solution for this. How should we do a deep insert in standard?
P.S. I don't want to use deep_create
Thanks
Best Regards
The create requests are currently being created asynchronously. The definitive parent ID will only be known in the frontend once the parent create request returns, but the requests to create the children are generated before this.
I can see two ways you could make sure the children will be created with the definitive parent id:
Send the parent and child create requests synchronously. Wait until the parent create request has returned succesfully before creating the children.
Send both as a change set. Let the implementation of the oData-service create the parent first and then the children with the now-created parent ID. (You are now setting changeId, the API specifies changeSetId)

Grid filled by a data provider: how to trigger an action after refreshment?

In Vaadin 8.2, I have a Grid bound to a bean using a data provider (AbstractBackEndDataProvider). Data is fetched from a DB, filters are applied:
Grid grid = new Grid<>();
grid.setDataProvider(dataProvider.withConfigurableFilter()); // dataProvider derives from AbstractBackEndDataProvider<T,F>
The essential flow is the following: user inputs an item id in a form and submits, a submit event listener gets the user input, creates a new filter and updates the data provider:
filterSubmitButton.addClickListener(event -> {
try {
ItemListFilter filter = new ItemListFilter(
itemFilter.getValue(), // itemFilter = new TextField();
);
filterBinder.writeBean(filter);
dataProvider.setFilter(filter);
} catch (ValidationException e) {
//...
}
});
When the data provider gets the filter updated it calls a service to fetch new items from DB with the filter applied (to the DB query). Vaadin takes care of refreshing the Grid with new data afterwards.
What I want is to have a callback at this last moment. Say an use case would be to check if a filtered fetched result set contains only one item, to select this item in the Grid (which in its turn will trigger an event showing item details in another pane). Or to select the first grid row after initial list is loaded
But the problem is that there is neither grid.addRefreshListener() nor dataProvider.addRefreshmentListener(). Any other listeners do not seem to apply in this case.
Thanks for any help in advance.
The only solution I've found is a trade-off.
The item list presenter (which handles the view with the grid) passes its com.vaadin.event.EventRouter to dataProvider (I've modified the dataProvider to hold an EventRounter as a member). And now instead of streaming DB results directly from the dataProvider I fire an event that the data is fetched (using EventRouter). The presenter can subscribe to this event and then delegate it to the presenter of the details panel. There you can read the fetched results (the event contains them), check if there's only one entry and open it by id.
public class ListItemDataProvider extends AbstractBackEndDataProvider<Item, ItemFilter> {
//...
#Override
protected Stream<Item> fetchFromBackEnd(Query<Item, ItemFilter> query) {
// ...
List<Item> fetchedResults = service.fetch(query.getOffset(), query.getLimit(), orderBy, getFilter(query));
eventRouter.fireEvent(new FilteredDataFetchedEvent(this, fetchedResults));
return fetchedResults.stream();
}
}
#Controller
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ItemListPresenter {
// ...
public void addFilteredDataFetchedListener(ItemListView.FilteredDataFetchedListener listener) {
eventRouter.addListener(FilteredDataFetchedEvent.class, listener, FilteredDataFetchedListener.FILTERED_DATA_FETCHED);
}
}
Few notes:
This is not exactly what I needed. Yes, I can do the most of my use case, if the filter is applied the list is reloaded and the details view gets the event to reload too. But I can't re-use the "selectionChanged" event listeners for this and actually can't select a row in the grid at all (just because the event from dataProdiver is thrown before the grid is updated).
This is sort of a dirty trick, because now the dataProvider throws events and deals with eventRouters of views/presenters. On the other hand Vaadins data providers anyway do allow to subscribe on events. Using that out-of-box grid-dataProvider reactive binding we just don't have an event fired after data is fetched, so we do it in a custom way.
What could also work is use the given Vaadin's subscriber dataProvider.addDataProviderListener and delegate from there an event containing the filled filter and just act independently catching that event in the details panel. But then you would need to execute sql queries twice (which can be costly) or cache them etc. This brings no benefits in comparison to the given and is still a trade-off.
When you invoke dataprovider.refreshAll(), the associated grid is automatially refreshed. Therefore, after following lines in your code:
filterBinder.writeBean(filter);
dataProvider.setFilter(filter);
add logic to get size of returned records (eg. dataprovider.size()) and if that equals one (01), invoke some other logic to select the one record and display its details in other panel.

How to load TreeView data only once in a _Layout page

Our users asked to have the Kendo Tree show up in the MVC web app in a panel on the left hand side of the page. They want that left hand panel to be present on every screen.
Currently I have a section of my _Layout.cshtml page that renders the Kendo Tree:
<div>
#{Html.RenderAction("GetTree", "Tree");}
</div>
Inside that Action I make a database call to get the contents of the tree and bind the model to the view as follows:
#model IEnumerable<TreeViewItemModel>
But obviously with this pattern every page I go to the _Layout gets called and the tree data is fetched from the database again. This is not very efficient.
What is a better way so that I only make a single database call?
I'm going to assume that the content of the tree is the same for every page and every user.
In that case, you can cache the retrieved database data so that you don't have to retrieve it on every page render. There are lots of ways to cache it: the simplest is probably to use ASP.NET's own caching, which is described in detail (with walkthroughs) here.
You probably will still have to render it on every page (unless you want to get into partial page caching, and I'm not sure how that works in MVC) but you definitely can avoid the repeated database hit.
ETA: You can create a wrapper or helper class that retrieves the necessary tree data by company. The relevant method would look a bit like this:
public IEnumerable<TreeViewItemModel> GetCachedTreeDataByCompany(int companyId)
{
var data = Cache["TreeData"] as IEnumerable<TreeViewItemModel>;
if(data == null)
{
data = GetTreeData(); // whatever you need to do to get the data
Cache.Insert("TreeData", data);
}
return data.Where(tvim => tvim.CompanyId == companyId).ToArray();
}

Grails dynamic display implementation (Partial page update)

I have a select field to choose the department. I want to implement a view that displays the list of employees working in that department. I want to display both the select field and list of employees in the same page(view). How is it possible to send the selected field parameter to the same controller and update the list of employees object and display the list in the same page.
There are three main parts to a partial page update. I will give you a general overview of how each part is composed with some examples. This should get you started on the right path. I'm having to make lots of assumptions since your question is light on details. However you should be able to take this information and write your won implementation.
Part 1 (Making the request)
This involves monitoring the select list for a change and sending the value of the selected option to the controller. JQuery is well suited for this. I am going to pretend that the select list has an id of "departmentId" and we want to put the contents of the employee list into an element with the id of "displayList".
<script type='text/javascript'>
<!--
(function() {
$("#departmentId").on("change", function() {
$.get("${g.createLink(controller: 'employeee', action: 'listForDepartment')}/"+$(this).val(), function(data) {
$("#displayList").html(data);
});
});
})();
// -->
</script>
Part 2 (Fulfilling the request)
The second part is our controller code for getting the list of employees. This is just an example of what it might look like. Notice that we are going to render a template instead of a view. This is very important because we don't want Grails (Sitemesh) to apply any layout to the results.
class EmployeeController {
...
def listByDepartment() {
def model = [:]
model['department'] = Department.get(params.id)
model['employees'] = Employee.findAllByDepartment(model['department'])
render template: 'employeeListForDepartment', model: model
}
...
}
Part 3 (Displaying the results in a template)
Finally, our template grails-app/views/employee/_employeeListForDepartment.gsp is going to display our employees for the department. Since we used the employee controller the template is inside the employee views and all templates begin with an underscore.
<h1>Employees for ${department.name}</h1>
<ul>
<g:each in="${employees}" var="employee">
<li>${employee.name}</li>
</g:each>
</ul>
Of course, the details of your implementation my be very different but the overall concept should be the same. This just touches on the main part of this and leaves a lot of details out, such as spinners, canceling requests, and such.

Adding related master/child entities (one to many) in breeze

I have a master file for a widget and there can be many versions of that widget that share the same widgetmaster. So there are widgetMasters and widgetVersions tables on the db.
widgetMaster ID is an identity integer field and has an icollection of widgetversions set.
Widgetversion has a foreign key pointing to the widgetMaster ID it belongs to.
I have a "create new widget" form on my site. This is loaded after a button is pressed and it uses "createEntity" to create blank entities for widgetMaster and widgetVersion. The idea is that the parent "widgetMaster" is created at the same time the version "001" is created. The master just contains the description and a few category fields. The version contains the specific fields relating to this version of the widget and there may be dozens of versions eventually.
The user fills in all the fields and presses "save".
At this point I validate the form fields and, if all is ok, move on to saving the entity via "datacontext.saveChanges()" This is done in the viewmodel for my "create new" form view.
This works fine when creating the widgetMaster, but I need to have more control of this process I think... I need to set the foreign key on the widgetVersion entity AFTER The id is created by "savechanges" but BEFORE it attempts to save the widgetVersion entity.
As "datacontext.saveChanges()" appears to be a one-stop shop I'm entirely baffled as to how I can save the widgetVersion entity with the newly-created ID from the widgetmaster I just saved.
Alrighty then. I can't say whether it's the best way of doing it, but here's how I accomplish it. Refer to this stackoverflow question for a bit more info: Breeze bug? It's trying to add related entity even though only the primary entity is specified in savechanges()
My viewmodel save method (on the form entry view that allows the user to populate the fields in the new entities) is now this:
var save = function () {
isSaving(true);
//1st save widgetMaster
return datacontext.saveChanges(new Array(newWidgetMaster())).then(function (saveResult) {
//set version entity to have master id
newWidgetVersion().widgetMasterID(newWidgetMaster().id());
return datacontext.saveChanges(new Array(newWidgetVersion())).fin(complete);
}).fail(function (e) {
//do something with the alert
});
function complete() {
isSaving(false);
}
};

Resources