I'm developing an Azure portal extension that includes an editable grid blade.
The grid's blade is opened from a selector and therefore contains a parameter provider.
The grid is initialized with the edit scope of the parameter provider, which is an observable array, and enabled for row editing and inserting new rows.
When I try to update the grid, changes to existing rows are not shown and creating new line yields an empty line, like below:
I don't see any errors in the console while debugging.
Here's how I initialized the grid:
private _initialize(container: MsPortalFx.ViewModels.PartContainerContract): void {
var extensions: number = MsPortalFx.ViewModels.Controls.Lists.Grid.Extensions.EditableRow | MsPortalFx.ViewModels.Controls.Lists.Grid.Extensions.ContextMenuShortcut,
extensionsOptions: MsPortalFx.ViewModels.Controls.Lists.Grid.ExtensionsOptions<DataModels.IItem, DataModels.ISelectionItem>,
viewModel: MsPortalFx.ViewModels.Controls.Lists.Grid.ViewModel<DataModels.IItem, DataModels.ISelectionItem>;
// Set up the editable extension options.
extensionsOptions = this._createExtensionsOptions();
// Create the grid view model.
viewModel = new MsPortalFx.ViewModels.Controls.Lists.Grid.ViewModel<DataModels.IItem, DataModels.ISelectionItem>(
container,
null,
extensions,
extensionsOptions);
viewModel.showHeader = true;
viewModel.columns(this._columns);
viewModel.rowAdd = () => {
// code that extension authors need to execute when a row is added should go here.
};
this.editableGrid = viewModel;
}
private _createExtensionsOptions(): MsPortalFx.ViewModels.Controls.Lists.Grid.ExtensionsOptions<DataModels.IItem, DataModels.ISelectionItem> {
return <MsPortalFx.ViewModels.Controls.Lists.Grid.ExtensionsOptions<DataModels.IItem, DataModels.ISelectionItem>>{
editableRow: {
// Supplies editable items to the grid.
editScope: this.parameterProvider.editScope,
// put the new row at the top.
placement: MsPortalFx.ViewModels.Controls.Lists.Grid.EditableRowPlacement.Bottom,
// Create no more than 5 new rows.
maxBufferedRows: 5,
// Allow the modification of existing items.
allowEditExistingItems: true,
// Allow the creation of new items.
allowEditCreatedItems: true,
// Track the valid status
valid: ko.observable<boolean>()
}
};
}
I've reviewed several sample blades of editable grid but couldn't identify what am I doing wrong.
The problem was that I didn't set the editScopeMetadataType property of the parameter provider, which required for determining the edit scope's entity type:
this.parameterProvider = new MsPortalFx.ViewModels.ParameterProvider<DataModels.IItem[], KnockoutObservableArray<DataModels.SchemaItem>>(container, {
// This was missing.
editScopeMetadataType: wrapperTypeMetadataName,
mapIncomingDataForEditScope: (incoming) => {
return ko.observableArray(incoming);
},
mapOutgoingDataForCollector: (outgoing) => {
return outgoing();
}
});
Related
I want to add a 3rd Inspector which will open only for an element(not a link) of specific type, for example only for basic.Rect in Rappid.
So far, there are 2 Inspectors.For elements and for links.
Is there any way it can be done?
The following code is a part of the KitchenSkink version of Rappid.
Here is function createInspector:
createInspector: function(cellView) {
var cell = cellView.model || cellView;
// No need to re-render inspector if the cellView didn't change.
if (!this.inspector || this.inspector.options.cell !== cell) {
// Is there an inspector that has not been removed yet.
// Note that an inspector can be also removed when the underlying cell is removed.
if (this.inspector && this.inspector.el.parentNode) {
this.inspectorClosedGroups[this.inspector.options.cell.id] = _.map(app.inspector.$('.group.closed'), function(g) {
return $(g).attr('data-name');
});
// Clean up the old inspector if there was one.
this.inspector.updateCell();
this.inspector.remove();
}
var inspectorDefs = InspectorDefs[cell.get('type')];
this.inspector = new joint.ui.Inspector({
inputs: inspectorDefs ? inspectorDefs.inputs : CommonInspectorInputs,
groups: inspectorDefs ? inspectorDefs.groups : CommonInspectorGroups,
cell: cell
});
this.initializeInspectorTooltips();
this.inspector.render();
$('.inspector-container').html(this.inspector.el);
if (this.inspectorClosedGroups[cell.id]) {
_.each(this.inspectorClosedGroups[cell.id], this.inspector.closeGroup, this.inspector);
} else {
this.inspector.$('.group:not(:first-child)').addClass('closed');
}
}
}
If you use joint.ui.Inspector.create('#path', inspectorProperties) any previous instance of the Inspector in a specific DOM element is removed and new one is created and rendered into the DOM automatically (it avoids creating a new instance of joint.ui.Inspector(), rendering it, adding the rendered result manually and removing the previous instance).
It also keeps track on open/closed groups and restore them based on the last used state.
Besides this, you may always have several different inspectorProperties objects previously defined when you are about to create() the inspector. So following the code you pasted, you could perform the tests you need first and then create the appropriate inspector:
if(cell instanceof joint.basic.Rect){
var customInputs = _.clone(CommonInspectorInputs);
// extend more inputs into `customInputs` from a variable previously defined
// OR modify the default rectangle's inspector directly, example:
customInputs.attrs.text = {
type: 'textarea',
label: 'Multiline text',
text: 'Type\nhere!',
group: joint.util.getByPath(CommonInspectorInputs.attrs, 'text/group', '/');
};
joint.ui.Inspector.create('.extra-inspector-container', {
cell: cell
inputs: customInputs,
groups: CommonInspectorGroups,
});
} // if only ONE inspector needs to be loaded add an ELSE block here
// and use '.inspector-container' in the `create()` above
// If `InspectorDefs` is a global variable with all the cells inspectors properties
// create and load the default inspector
joint.ui.Inspector.create('.inspector-container', _.extend({cell: cell},
InspectorDefs[cell.get('type')])
);
I'm trying to add a new empty line in ui-grid. I've tried looking in different tuto and example, but all that I found didn't reply to my spec, and I wasn't able to adapt it to what I'm looking for.
In fact I'm looking how to add a new empty line in an existing ui-grid neither using a button outside the grid nor a button in the rowfooter.
I'm looking to add a abutton in the grid like the + button shown in the screen shot below
or may be render automatically a new empty line when the rendering the ui-grid and a new one when all rows were filled.
I tried doing that using function in cell template but it's not working.
any help is really appreciated
The first option sounds like more of a CSS issue to me. Essentially, the add button would use some sort of font library containing a +, and you would need to position it in the corner of the grid. Perhaps looking at the grid footer would be a starting place. It sounds like you've seen the basics of creating an add row button here: http://ui-grid.info/docs/#/tutorial/112_swapping_data
The second option (render automatically a new empty line when the rendering the ui-grid and a new one when all rows were filled) requires a JavaScript approach.
The basic logic I followed is:
(Assume) Some data loads from somewhere in a backend (in this sample, it's a simulated load returning a promise as $http or $resource would).
After that data is loaded, we append a new row. We wait for the data first; otherwise we'd not be pushing the new row to the correct location.
Upon completion of the edit action, we set a timeout to ensure subsequent edits on other cells do not keep firing a new row. If the timeout is reached, we append a new row. If a subsequent edit action occurs, and a timeout promise exists (for adding a new row), we cancel it. Once no edit actions occur, and the timeout is reached, we push the new row.
To ensure that we are only taking action when our "extra row" is modified, when we create a row, a reference is maintained to the current row such that we can evaluate whether or not a received event is of interest (var newRowTimeoutPromise).
The core logic in code is below, with a sample implementation in Plnkr:
var extraRow = null,
addNewTimeoutMillis = 2000,
newRowTimeoutPromise = null;
loadData().then(function(data) {
$scope.gridOpts.data = data;
}).finally(function() {
// add initial empty row, and set our reference to it
extraRow = addEmptyRow($scope.gridOpts.data);
})
$scope.gridOpts = {
showGridFooter: true,
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
// listen for cell edit completion
gridApi.edit.on.afterCellEdit($scope, function(rowEntity, colDef, newValue, oldValue) {
// test if the edited row was the "extra row"
// otherwise, and edit to any row would fire a new row
// Set a timeout so we don't create a new row if the user has
// not finished their edit(s) on other fields
newRowTimeoutPromise = $timeout(function() {
if (rowEntity == extraRow) {
// add a new empty row, and set our reference to it
extraRow = addEmptyRow($scope.gridOpts.data);
newRowTimeoutPromise = null;
}
}, addNewTimeoutMillis);
})
// Listen for cell edit start, and cancel if we have a pending new
// row add. Otherwise, each time you finish the edit on a cell,
// this will fire.
gridApi.edit.on.beginCellEdit($scope, function(rowEntity, colDef, newValue, oldValue) {
if (newRowTimeoutPromise != null) {
$timeout.cancel(newRowTimeoutPromise);
}
})
}
};
http://plnkr.co/edit/IMisQEHlaZDCmCSpmnMZ?p=preview
I used jQuery to fetch and change style of specific cell elements of the cell template.
Here is a helpful Fiddle
Here is the controller script : -
var app = angular.module('app', ['ngTouch', 'ui.grid']);
app.controller('MainCtrl', ['$scope',
function($scope) {
$scope.gridOptions = {};
$scope.Add = function() {
$scope.gridOptions.data.push( { firstName: ' ',lastName:'',company:'' });
$(".ui-grid-coluiGrid").prevObject["0"].activeElement.style.display="none";
$(".ui-grid-cell")[$scope.gridOptions.data.length-2].style.display="inline";
};
$scope.gridOptions.onRegisterApi = registerGridApi;
function registerGridApi(gridApi) {
$scope.gridApi= gridApi
};
$scope.gridOptions.columnDefs = [{
name: 'firstName',
field: 'firstName',
}, {
name: 'lastNamer',
field: 'firstName'
}, {
name: 'ShowScope',
cellTemplate: '<button id="btb" ng-click="grid.appScope.Add()">+</button>'
}];
$scope.gridOptions.data = [{ yourdata}];
}
]);
To make it work properly 2 more things have to be done
Use cellContentEditable to make the rows editable
In order to disable display style of cell template button that appears on cells corresponding to rows of already existing data,you could use angular foreach or a for loop to iterate through these rows and disable style(I tried using renderContainers but it always returns the length of rendered rows outside Add functions as 0).
I have a working plunker over here.
http://plnkr.co/edit/Vnn4K5DcCdiercc22Vry?p=preview
In columnDefs, I have defined a separate column for add:
{
name: 'add',
displayName: '',
enableCellEdit: false,
enableColumnMenu: false,
width: '3%',
cellTemplate: '<div class="ui-grid-cell-contents" ng-click="grid.appScope.addRow()"><span ng-click="grid.appScope.addRow()">Add</span></div>'
}
And
$scope.addRow= function(){
var newlist = {"remarks":'',"testName":''};
$scope.gridOptions.data.push(newlist);
}
Update: A second plunker with bootstrap icons for add/remove
http://plnkr.co/edit/FjsA2r?p=preview
I am working on setting up a scenario as following:
1) User is shown existing results on first grid
2) User can select multiple results and click an 'Edit' button which will extract the selected items from the first grid
3)Second grid will be populated with the rows the user has selected from the first grid and will allow them to make edits to the content
4)Pressing save will update the results and show the first grid with the rows updated
So far using drips and drabs of various forum threads (here and here), I have managed to accomplish the first two steps.
$("#editButton").kendoButton({
click: function () {
// extract selected results from the grid and send along with transition
var gridResults = $("#resultGrid").data("kendoGrid"); // sourceGrid
var gridConfig = $("#resultConfigGrid").data("kendoGrid"); // destinationGrid
gridResults.select().each(function () {
var dataItem = gridResults.dataItem($(this));
gridConfig.dataSource.add(dataItem);
});
gridConfig.refresh();
transitionToConfigGrid();
}
});
dataItem returns what i am expecting to see with regards to the selected item(s) - attached dataItem.png. I can see the gridConfig populating but with blank rows (gridBlankRows.png).
gridConfig setup:
$(document).ready(function () {
// build the custom column schema based on the number of lots - this can vary
var columnSchema = [];
columnSchema.push({ title: 'Date Time'});
for(var i = 0; i < $("#maxNumLots").data("value"); ++i)
{
columnSchema.push({
title: 'Lot ' + i,
columns: [{
title: 'Count'
}, {
title: 'Mean'
}, {
title: 'SD'
}]
});
}
columnSchema.push({ title: 'Comment'});
columnSchema.push({ title: 'Review Comment' });
// build the datasource with CU operations
var configDataSource = new kendo.data.DataSource({
transport: {
create: function(options) {},
update: function(options) {}
}
});
$("#resultConfigGrid").kendoGrid({
columns: columnSchema,
editable: true
});
});
I have run out of useful reference material to identify what I am doing wrong / what could be outstanding here. Any help/guidance would be greatly appreciated.
Furthermore, I will also need functionality to 'Add New' results. If possible I would like to use the same grid (with a blank datasource) in order to accomplish this. The user can then add rows to the second grid and save with similar functionality to the update functionality. So if there is any way to factor this into the response, I would appreciate it.
The following example...
http://dojo.telerik.com/EkiVO
...is a modified version of...
http://docs.telerik.com/kendo-ui/framework/datasource/crud#examples
A couple of notes:
it matters if you are adding plain objects to the second Grid's dataSource (gridConfig.dataSource.add(dataItem).toJSON();), or Kendo UI Model objects (gridConfig.dataSource.add(dataItem);). In the first case, you will need to pass back the updated values from Grid2 to Grid1, otherwise this will occur automatically;
there is no need to refresh() the second Grid after adding, removing or changing its data items
both Grid dataSources must be configured for CRUD operations, you can follow the CRUD documentation
the Grid does not persist its selection across rebinds, so if you want to preserve the selection in the first Grid after some values have been changed, use the approach described at Persist Row Selection
I do have a jqGrid with inline editing (EditActionIconsColumn = true). I want to change the properties of edit fields when use click on edit icon in Action column of jqGrid. For this implementation, I am looking for an event which occurs after the row gets ready for user modifications.
I am not using grid.editRow(). I am using action column where EditActionIconsColumn = true.
I am trying something like
$("#grid1").jqGrid().on("editRow", function() {
});
But not working. Did any one tried this methodology for jqGrid?
I have used EditActionIconsColumn in server code like below with reference to the demo (Inline Row> Editing: Action Icons (save, delete, cancel))
public void EditRowInlineActionIcons_SetUpGrid(JQGrid ordersGrid)
{
ordersGrid.Columns.Insert(0, new JQGridColumn
{
EditActionIconsColumn = true,
EditActionIconsSettings = new EditActionIconsSettings
{
SaveOnEnterKeyPress = (bool?) ViewData["enterData"] ?? false,
ShowEditIcon = (bool?) ViewData["editData"] ?? true,
ShowDeleteIcon = (bool?) ViewData["delData"] ?? true
},
HeaderText = "Edit Actions",
Width = 50
});
ordersGrid.DataUrl = Url.Action("EditRowInlineActionIcons_DataRequested");
ordersGrid.EditUrl = Url.Action("EditRowInlineActionIcons_EditRow");
// setup the dropdown values for the CustomerID editing dropdown
EditRowInlineActionIcons_SetUpCustomerIDColumn(ordersGrid);
}
I have a KoGrid and want to be able to save visible columns when a user revisits the page. I would save data in json to a cookie or on the database, but how can I get notified when a column's visible attribute is changed, and load visibility on initialization?
Its easy achieved with some creative overrides of the kg.grid constructor
http://jsfiddle.net/A29GA/2/
var savedState = { age: false, name: true };
var org = kg.Grid;
kg.Grid = function (options) {
var grid = new org(options);
ko.utils.arrayForEach(grid.columns(), function(col) {
//load state from cookie
col.visible(savedState[col.field]);
});
grid.visibleColumns.subscribe(function() {
console.log("Here you get notified when visible columns change save to cookie");
});
return grid;
};
Here is a example that uses actual cookies, but I wouldnt rely on the cookie code, its quick and dirty
http://jsfiddle.net/A29GA/3/