I have a Vaadin grid that I use. I make a put request to update the scores of the elements in the grid. I was wondering how to make the grid respond after the update to show the new information. Right now I have to refresh the entire page to show the new information.
I'm not sure what code I would post, I'm using a basic vaadin grid if that helps.
I am not completely sure with what you mean by putting changes to the grid, but I suppose you are using setItems or a data provider?
For the first, you would have:
Grid<MyItem> grid = new Grid(MyItem.class);
grid.setItems(someItems);
While for the second you would write:
Grid<MyItem> grid = new Grid(MyItem.class);
grid.setDataProvider(...);
For the second way you can either specify the data provider using Java 8 notation as in:
grid.setDataProvider(
(sortOrders, offset, limit) -> {//e.g. call to repo },
() -> { // count provider, e.g. repo.count() });
or as in:
grid.setDataProvider(new ListDataProvider<>(myDataCollection));
To come to the question, in both cases you can call following to get the provider:
DataProvider<MyItem> provider = grid.getDataProvider();
To update one specific element, the data provider provides the method
provider.refreshItem(item);
Important to know is that the MyItem class has to implement a getId() method, or, alternatively, equals(). If this is not the case, you can invoke provider.refreshAll()
Related
I have two pairs of controller and view. The first view contains a list of items, while the in second shows some details of a specific item. What I want to achieve is that a click on one list item, the function onSelect should call second controller of detail view and update its content with the selected list item.
So far I have following code:
//first list controller
onSelect : function () {
var secondController = sap.ui.controller("controller.Detail");
secondController.updateFunction("some text");
}
Then in second controller:
//second detail-controller
updateFunction: function (someText) {
var view = sap.ui.xmlview("view.Detail");
view.byId("someTextField").setText(someText);
}
The problem is that this is not working. It seems that sap.ui.xmlview is not returning the same view which is displayed.
When I execute following code:
var model = view.getModel(model);
console.log(model);
within 2 functions of detail controller, but first is called by outside controller and second is called by onInit or function called by detail view event, the id is different.
How can I achieve such a cross-controller function calling with updating content of different view? Or is my approach not proper?
I would recommend to use either the EventBus or Routing for inter view communication.
Routing is nice as it uses the hash part (#) of the url to communicate for example an event like the selection of an item (f.e. https://example.com/myUi5App/index.html#/item/123). The user can use the browser history and bookmarks to navigate through your app.
A view can register to the router to be notified when a specific url pattern is matched. The walkthrough in the SAPUI5 Developer Guide does nicely explain routing step by step and in detail here and here.
EventBus is a global object that can publish arbitrary events. Anyone interested can register to the EventBus. There is an EventBus on the Component which you should use if you have a component and a global EventBus.
Both techniques help decoupling your views. It does not matter if there are one, many or none views listening to the selection change. And it does not matter for the listeners who fired the event.
If both views have been called once you can achieve this via the view (from my opionion, this is quite hacky and should be solved otherway)
this.getView().byId("yourViewId").oController.yourMethod();
means in your case
onSelect : function () {
var secondController = this.getView().byId("view_id").oController;
secondController.updateFunction("some text");
}
maybe this helps you, he is passing the controller reference which would be a better option: Calling Controller Function from inside a press handler in sapui5
I have found solution.
sap.ui.getCore().byId("__xmlview1");
According to documentation var view = sap.ui.xmlview("view.Detail"); always creates a new view.
However I am still struggling about specifying id of xmlview. Since "___xmlview1" is dynamicly given name and the number 1 means serial number of views within application. So if I create another view before creation of "view.Detail", the id will point to the new one.
I am creating xmlview like this:
<mvc:XMLView viewName="view.Detail"></mvc:XMLView>
This issue is bugging me for some time now. To test it I just installed a fresh Apigility, set the db (PDO:mysql) and added a DB-Connected service. In the table I have 40+ records. When I make a GET collection request the response looks OK (with the default HAL content negotiation). Then I change the content negotiation to JSON. Now when I make a GET collection request my response contains only 10 elements.
So my question is: where do I set/change this limit?
You can set the page size manually, like so:
$paginator = $this->getAlbumTable()->fetchAll(true);
// set the current page to what has been passed in query string, or to 1 if none set
$paginator->setCurrentPageNumber((int) $this->params()->fromQuery('page', 1));
// set the number of items per page to 10
$paginator->setItemCountPerPage(10);
http://framework.zend.com/manual/current/en/tutorials/tutorial.pagination.html
Could you please send the page_size, total_items part at the end of the json output?
it's like:
"page_count": 140002,
"page_size": 25,
"total_items": 3500035,
"page": 1
This is not an ideal fix, because it requires you to go into the source code rather than using the page size given in the UI.
The collection class that is auto generated for you by the DB-Connected style derives off of Zend/Paginator/Paginator. This class defines the $defaultItemCountPerPage static protected member which is defaulted to 10. That's why you're only getting 10 results. If you open up the auto-generated collection class for your entity and add: protected static $defaultItemCountPerPage = 100; in the otherwise empty class, you will see that you now get up to 100 results in the response. You can look at other Paginator class variables and methods that you could replace in your derived class to get your desired behavior.
This is not an ideal solution. I'd prefer that the generated code automatically used the same configed page size that the HalJson strategy uses. Maybe I'll contribute a PR to change that. Or, maybe I'll just use the HalJson approach. It does seem like the better way to go. You should have some limit to how much data you load in from the DB at a time to not have an overly long running query or an overly large collection of data coming back you have to deal with. And, whatever limit you set, what do you do when you hit that limit? With the simple Json method, you can't ever get "page 2" of data. So, if you are going to work with some sizeable amount of data, it might be better to use HalJson on and then have some logic on the client side to grab pages of data at a time as needed. The returned JSON structure is a little more complicated, but not terribly so.
I'm probably in the same spot you are -- I'm trying to do a simple little api to play with while keeping everything simple and so I didn't want the client to have to deal with the other stuff in HalJson, but probably better to deal with that complexity and have a smooth way to page through data if you're going to use this with some real set of data. At least, that's the pep talk I'm giving myself right now. :-)
I have built a MVCPortlet that runs on Liferay 6.2.
It uses a PortletPReferences page that works fine to set/get String preferences parameters via the top right configuration menu.
Now I would need to store there a String[] instead of a regular String.
It seems to be possible as you can store and get some String[] via
portletPreferences.getValues("paramName", StringArrayData);
I want the data to be stored from a form multiline select.
I suppose that I need to call my derived controller (derived from DefaultConfigurationAction) and invoke there portletPreferences.setValues(String, String[]);
If so, in the middle, I will neeed the config jsp to pass the String[] array to the controller via a
request.setAttribute(String, String[]);
Do you think the app can work this way in theory?
If so, here are the problems I encountered when trying to make it work:
For any reason, in my config jsp,
request.setAttribute("paramName", myStringArray);
does not work ->
actionRequest.getAttribute("paramName")
retrieves null in my controller
This is quite a surprise as this usually works.
Maybe the config.jsp works a bit differently than standard jsps?
Then, how can I turn my multiline html select into a String[] attribute?
I had in mind to call a JS function when the form is submitted.
this JS function would generate the StringArray from the select ID (easy)
and then would call the actionURL (more complicated).
Is it possible?
thx in advance.
In your render phase (e.g. in config.jsp) you can't change the state of your portlet - e.g. I wouldn't expect any attributes to persist that are set there. They might survive to the end of the render phase, but not persist to the next action call. From a rendered UI to action they need to be part of a form, not request attributes.
You can store portletpreferences as String[], no problem, see the API for getting and setting them
I think maybe you can use an array in client side, and you can update the javascript array, when user is selecting new values.
So you have the javascript array, then when user click on the action, you can execute the action from javascript also, something like this:
Here "products" is the array with your products.
A.io.request(url, {type: 'POST',
data: {
key: products
},
on: {
success: function(event, id, obj) {
}
}
});
From Action methd you can try to get the parameter with:
ParamUtil.getParameterValues(request,"key");
I am using knockout mapping plugin to map JSON data to knockout view model. The issue is JSON comes from server data doesn't have all the properties always. But my computed obeservables refer them. So I creates all the observable in first mapping using an empty object(templateStructure) contains all properties and then doing seocond call with actual data to populate the observable with current data. This works fine but want to know that if there any better way to handle the situation?
This is how the two time call is happening right now. templateStructure is dummay object with all the properties and data is actual data.
ko.mapping.fromJS(templateStructure, {}, this);
ko.mapping.fromJS(data, {}, this);
Calling mapping.fromJS to update an existing view model is right. If you're receiving updates to your model using AJAX, it's the easiest way to do it (if you didn'd use mapping, you'd have to do it by hand, property by property).
Your approach of creating a "template viewmodel" with all the properties, so that they exist even if you don't receive it in you JSON responses is good. Besides, it's easier to understand the JavaScript code: you don't need to see the server side to discover which properties are in the view model, as would happen if you made the first mapping directly from the server.
However, if the received model is nearly complete, you can always customize the "create" of your mapping (You could look for missing observable properties using js hasOwnProperty and adding the missing ones). The last example of the docs in the link so precisely how to add a new observable (in this sample, a computed observable):
var myChildModel = function(data) {
ko.mapping.fromJS(data, {}, this); // this is the view model
this.nameLength = ko.computed(function() { // nameLength is added to the vm
return this.name().length;
}, this);
}
In this sample you could add the condition to create nameLength only if not present on the received data, like this:
if (!data.hasOwnProperty('nameLength')) {
/* add the missing observ. property here */
}
(NOTE: you can also customize the update, if needed).
I have solved it using jQuery extend method by merging the object before mapping. So I only needed one call to the mapping function.
var mergedData = jQuery.extend(true,data,templateStructure);
ko.mapping.fromJS(mergedData, {}, this);
I have tried using a few different data grids (FlexiGrid, ExtJs Grid, and YUI DataGrid) and have found YUI to work the best as far as documentation and features available. However, I am having difficulty setting up the data source. When I try to set it up using JSON, it takes too long, or times out. I have already maxed out the memory usage in the php.ini file. There will be many more records in the future as well.
I need to select data to populate the grid based on the user that is currently logged in. Once this information populates the grid, I need each id to be click-able and take me to a different page, or populate information in a div on the same page.
Does anyone have suggestions on loading 25 – 50 records at a time of dynamic data? I have tried implementing the following example to do what I want: YUI Developer Example
I cannot get the data grid to show at all. I have changed the data instance to the following.
// DataSource instance
var curDealerNumber = YAHOO.util.Dom.getElementsByClassName('dealer_number', 'input');
var ds_path = + "lib/php/json_proxy.php?dealernumber='" + curDealerNumber + "'";
var myDataSource = new YAHOO.util.DataSource("ds_path");
myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
myDataSource.responseSchema = {
resultsList: "records",
fields: [
{key:"id", parser:"number"},
{key:"user_dealername"},
{key:"user_dealeraccttype"},
{key:"workorder_num", parser:"number"},
{key:"segment_num", parser:"number"},
{key:"status"},
{key:"claim_type"},
{key:"created_at"},
{key:"updated_at"}
],
metaFields: {
totalRecords: "totalRecords" // Access to value in the server response
}
};
Any help is greatly appreciated, and sorry if this seems similar to other posts, but I searched and still could not resolve my problem. Thank you!
It's hard to troubleshoot without a repro case, but I'd suggest turning on logging to see where the problem might be:
load datatable-debug file
load logger
either call YAHOO.widget.Logger.enableBrowserConsole() to output logs to your browser's JS console (i.e., Firebug), or call new YAHOO.widget.LogReader() to output logs to the screen.
Also make sure the XHR request and response are well-formed with Firebug or similar tool.
Finally, when working with large datasets, consider
pagination
enabling renderLoopSize (http://developer.yahoo.com/yui/datatable/#renderLoop)
chunking data loads into multiple requests (http://developer.yahoo.com/yui/examples/datatable/dt_xhrjson.html).
There is no one-size-fits-all solution for everyone, but hopefully you can find the right set of tweaks for your use case.