Generic dashboard state on Thingsboard - thingsboard

I have a entity admin table that navigates to a dashboard state for a specific row on row click.
I want to have a default dashboard state and on row click populate the dashboard with the data of the device. This needs to be repeated for multiple devices.
How would I go about doing this?

You need to set the state entity. In your row click action, if you are using a simple logic one, be sure to tick the "Set entity from widget" checkbox.
Then in the target dashboard state, you need to include an entity alias as below.
Text desc of image:
Alias Name: state entity
Filter Type: Entity from dashboard state
Resolve as multiple: False
Others: None (leave empty)
This will mean that all widgets using this alias will dynamically change based on the current "state entity". You can change the state entity multiple ways, but I recommend to minimise the places that you do this. It can get complicated fast.
If you are not using a simple widget action, and instead using a custom widget action, you will need to use the following code to set the state entity.
function updateDashboardState(stateId, label) {
var params = {
entityId: entityId,
entityName: entityName,
entityLabel: label, // Optional
};
// Line below opens new state
widgetContext.stateController.openState(stateId,
params, false);
// Line below updates state
// widgetContext.stateController.updateState(stateId,
params, false);
}

Related

Is there a way to enable row editing on only new added rows within a Kendo grid?

So I have a standard Kendo grid in MVC with 2 non-editable columns. What I would like to achieve is to enable editing of all columns only within the newly added rows.
Example: There's 4 rows already in the grid, first 2 columns non-editable. User clicks "Add new", a new record appears in the grid with everything editable.
Try adding an editable function handler to your column definition, something like this:
{
field: "salary",
editable: function (dataItem) {
return dataItem.isNew();
}
}
Please note: you will need to have specified an id column in your model definition for this to work, for details see isNew documentation:
Checks if the Model is new or not. The id field is used to determine if a model instance is new or existing one. If the value of the field specified is equal to the default value (specified through the fields configuration) the model is considered as new.

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 prevent OData service call on model change

I have a sap.m.Table whose "items" are bound to oData v2 model. I need to delete item on click on delete icon. Here is what I do:
On click of delete icon, I get all the rows in the model, delete the one in question and set the property of model again.
However since the model is changed, it triggers a backend round trip and brings the latest data and table shows the original rows again.
I tried setting binding mode to OneTime but that does not work. Also tried setting RefreshAfterChange to false but even then service was called again.
Here is my code -
Controller
onInit: function() {
var oModel = new sap.ui.model.odata.v2.ODataModel("url", {
json: true,
useBatch : false,
refreshAfterChange: false,
defaultBindingMode: "OneTime"
});
this.getView.().setModel(oModel, "model1");
},
onDeleteIconPress : function(oEvent) {
// get the selected row
// get all the rows in oOriginalRows
// loop over oOriginalRows and delete the selected row from it
// set the model to reformed oOriginalRows
this.getView().getModel("omodel1").setProperty("/", oOriginalRows);
// Till this point every thing looks fine. I can see changes in the model
// refresh is called automatically and data service triggers backend call
// This fetches original data again and table shows all data again
}
How can I not trigger the round trip again? I need to update the locally
Your approach won't work with a ODataModel as it is strictly server side. Please use the corresponding remove method to delete an entity from the server.
Since Odata is server side model, it always triggered a round trip. So I did not bind my sap.m.Table to Data model. Instead I triggered a read manually. On success I copied the data received to local JSON model. I bound my table items to this JSON model. Now the delete button works just fine.
// Define a JSON Model
oJsonModel = new sap.ui.model.json.JSONModel();
//oModel is Odata model defined in manifest file
oModel.read("/entity1", {
success: function(oData, oResponse){
oJsonModel.setProperty("/entity1", oData.results);
// bind oJsonModel to table here
}
}

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);
}
};

Sending custom values on save and update using Telerik Grid

I have a Telerik grid in my asp.net mvc application that looks something like:
Now it lists all the regions in a zone selected from the list placed just above the grid. zoneid is foreign key in the grid. Now I want that when I add new region in the grid the zoneID should be taken from the list instead of what is present in zone column of the grid because that value is just to display the zone and that can also be removed from the grid as it as apparent from the list which zone the listed regions belong to.
I understand that I could have used editor templates to show this list inside the grid on edit but I prefer it to be outside the grid and provide some filtering on basis of the zone as we are likely to have many regions per zone. so my concern here, now, is how can I set ZoneID of a region (edited or newly added) equal to selected value of list that shows just above the grid control.
When you click on the AddNewRecord button, why don't you set the Value of your zone equals to the zoneId selected in the combobox value ?
I've done something a little similar, but I had to get the value from a Treeview.
private void btnAddContact_Click(object sender, EventArgs e)
{
Int64 companyId = Int64.Parse(treeCompany.SelectedNode.Name);
dsSociete.ContactRow newContact = dsSociete.Contact.NewContactRow();
newContact.SocieteId = societeId;
dsSociete.Contact.AddContactRow(newContact);
}
And once i add a new Contact, it gets automatically its Company (Societe is Company in French) set.
I did it in Winform, but I guess you can do the same in Web?
I solved this problem by hooking the onSave event of Telerik grid like
<%
Html.Telerkik.Grid<xyz.company>()
.Name("name")
.// other properties
.Events(even=>even.onSave("onSave")
.Render();%>
Inside onSave event handler in JS I have written something like
function onSave(e)
{
var data = e.values;
data["companyID"] = $("#CompanySelectList").val();
e.values = data;
return true;
}
onSave event adds the companyID at companyID index of json that will be submitted to the server and modelbinder will bind it with concerning property name of model.

Resources