I have a table that is populated by OData but I want it to not populate when first loading the page.
How can I have it be empty until the user selects a choice in the combo box first? Is there suppose to be a change in the view, controller, or manifest?
View
<ComboBox id="officeComboBox"
width="100%"
placeholder="Office"
selectionChange=".officeComboChange"
>
<items>
<core:Item key="{OFFICE_CODE}" text="{OFFICE_CODE}" textDirection="RTL"/>
</items>
</ComboBox>
<!-- ... -->
<Table id="statTable"
noDataText="Initializing Data"
growing="true"
includeItemInSelection="true"
headerText="EST"
items="{/ESTSet}"
>
Controller
Handler officeCodeChange works fine for displaying the right items on the table after combo box selection
onInit: function() {
var oViewModel, iOriginalBusyDelay, oTable = this.byId("officeCombo");
this._oTableSearchState = [];
},
officeCodeChange: function(event) {
var aFilters = [];
var officeCode = event.getParameter("selectedItem").getText();
var filter = new Filter("EST_ID", sap.ui.model.FilterOperator.Contains, officeCode);
var list = this.getView().byId("statTable");
var binding = list.getBinding("items");
binding.filter(aFilters.concat(filter), "Application");
},
Remove the initial aggregation binding items="{/ESTSet}" and the corresponding template control from the view.
Use bindItems in combination with the created filter(s):
officeCodeChange: function(event) {
const filter = /*...*/;
const table = this.byId("statTable");
const listBinding = table.getBinding("items");
if (listBinding) {
listBinding.filter(filter, FilterType.Application); // FilterType required from "sap/ui/model/FilterType"
} else {
this.bindStats(table, filter);
}
},
bindStats: function(table, filter) {
table.bindItems({
path: "/ESTSet",
filters: [filter],
template: new ColumnListItem({ // required from "sap/m/ColumnListItem"
//...
}),
});
},
Related
I have dynamically attached live search event for my Multi Input control (please refer the below code). Even after attaching the .bindAggregation function for suggestionItems, the suggestion popup doesn't appear.
onAfterRendering: function(oEvent){
var that = this;
var oFacetFilters = sap.ui.getCore().byId
("xyzID").getContent()[0].getContent();
var oCapTreeFilter = oFacetFilters[6].getContent()[1];
oCapTreeFilter.attachLiveChange(function(oEvt){
//build filter array
var aFilter = [];
var sQuery = oEvt.getParameter("value");
if (sQuery) {
aFilter.push(new sap.ui.model.Filter("RootID",
sap.ui.model.FilterOperator.Contains, sQuery));
}
that.oModel.read("/RootName", {
async : false,
filters : aFilter,
success : function(oData, response){
var oJSONModel = new sap.ui.model.json.JSONModel();
oJSONModel.setData(oData);
oCapTreeFilter.setModel(oJSONModel);
oCapTreeFilter.bindAggregation("suggestionItems",{
path: "/results",
template: new sap.ui.core.Item({text: "{RootID}"})
});
},
error : function(response){
sap.m.MessageBox.show("Error occurred");
}
});
});
My requirement is to build lightning datatable dynamically.
I can able to dynamically create and view lightning data table. But as soon as I am adding "onrowselection":component.getReference("c.getSelectedRecord") line, datatable is not rendering. So adding this line is causing the issue, but I need to hookup onrowselection event.
What is the proper way to add onrowselection event dynamically to my dynamically created datatable?
Error Reproduce: I have prepared demo code below.
Component: demoDynamicDataTable.cmp
<aura:component controller="demoDynamicDataTableController">
<aura:attribute name="returnList" type="Contact[]" access="public"/>
<aura:attribute name="returnColumns" type="List" access="public"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<lightning:button label="Create Data Table" onclick="{!c.createDT}" variant="brand"/>
<div aura:id="newDtPlaceholder">
{!v.body}
</div>
</aura:component>
JS Controller: demoDynamicDataTableController.js
({
doInit : function(component,event,helper) {
console.log("doinit");
//Column data for the table
var columns = [
{
label:'Customer Name',
fieldName:'Name',
type:'text'
},
{
label:'Phone#',
fieldName:'Phone',
type:'text'
}
];
//pass the column information
component.set("v.returnColumns",columns);
//recriving data from server
helper.fetchData(component);
},
createDT : function(component, event, helper) {
//Creating dynamic Lightning datatable
var targetCmp=component.find("newDtPlaceholder");
targetCmp.set("v.body",[]); //destroying existing one
$A.createComponent(
"lightning:datatable",
{
"data":component.get("v.returnList"),
"columns":component.get("v.returnColumns"),
"keyField":"Id",
"maxRowSelection":"1",
"onrowselection":component.getReference("c.getSelectedRecord") //adding this line is causing the issue. But I need to hookup onrowselection event
},
function(tbl,state,message)
{
console.log(state +" - " +message);
var body=targetCmp.get("v.body");
body.push(tbl);
targetCmp.set("v.body",body);
}
);
},
getSelectedRecord: function(component, event, helper){
var selectedRows = event.getParam('selectedRows');
console.log(JSON.stringify(selectedRows[0]));
}
})
Helper: demoDynamicDataTableHelper.js
({
fetchData : function(cmp) {
var action = cmp.get("c.getContact");
action.setCallback(this,function(resp){
var state = resp.getState();
if(state === 'SUCCESS'){
var records = resp.getReturnValue();
//console.log(JSON.stringify(records));
//pass the records to be displayed
cmp.set("v.returnList",records);
}
});
$A.enqueueAction(action);
}
})
Apex Controller: demoDynamicDataTableController.apxc
public class demoDynamicDataTableController {
#AuraEnabled
public static List<Contact> getContact(){
return [Select Id,Name,Phone from Contact];
}
}
App: demoDynamicDataTableApp.app
<aura:application extends="force:slds">
<c:demoDynamicDataTable/>
</aura:application>
In a table I have a checkbox bound to a bool in an observable array.
If any of the checkboxes in the table are checked / unchecked I want to update some text with the total checked.
I cannot get the computed function to fire, I have tried using ko.utils.unwrapObservable on both the array and location.isSelected in the 'if' statement below, am I just using it in the wrong place?
<input type="checkbox" data-bind="checked: isSelected"/>
<span class="text-left h5 ">Total Selected:</span><span data-bind="text: totalSelected" />
self.totalSelected = ko.computed(function () {
var selected = 0;
ko.utils.arrayForEach(self.SelectedLocations(), function (location) {
if (location.isSelected == true) {
selected = (+selected) + 1;
}
});
return selected;
}, self).extend({ notify: 'always' });
One of the issues is that isSelected is treated like a variable inside the computed: location.isSelected == true. However, if you intend to bind a checkbox to it, it must be an observable.
So, I have declared a function to create the children of self.SelectedLocations as:
var locationObservable = function() {
var self = this;
self.isSelected = ko.observable(false);
};
Then, you could change the counting in the computed variable as follows:
if (loc.isSelected()) {
selected++;
}
var locationObservable = function(selected) {
var self = this;
self.isSelected = ko.observable(selected);
};
var model = function() {
var self = this;
self.SelectedLocations = ko.observableArray();
self.SelectedLocations.push(new locationObservable(false)); // Set the state of the checkbox here.
self.SelectedLocations.push(new locationObservable(true));
self.SelectedLocations.push(new locationObservable(false));
self.totalSelected = ko.computed(function() {
var selected = 0;
ko.utils.arrayForEach(self.SelectedLocations(), function(loc) {
if (loc.isSelected()) {
selected++;
}
});
return selected;
}, self);
};
var vm = new model();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: SelectedLocations">
<input type="checkbox" data-bind="checked: isSelected" />
</div>
<span class="text-left h5 ">Total Selected:</span><span data-bind="text: totalSelected" />
I am new to hybrid mobile app creation. And my use case is very simple. I have a single ionic modal using template html.
What I want is populating the same ionic template with different values based on some records data. Basically it is a google map and on click on any of the markers, the same template should open with different values based on the marker.
My controller code -
.controller('MyLocationCtrl', function(
$scope,
$stateParams,
force,
$cordovaGeolocation,
$ionicModal,
GoogleMapService,
ForceService,
$q
) {
console.log('this is in my location page');
var currentPosition = GoogleMapService.getCurrentLocation();
var restaurantModal = $ionicModal.fromTemplateUrl('templates/bottom-sheet.html', {
scope: $scope,
viewType: 'bottom-sheet',
animation: 'slide-in-up'
});
var allContacts = ForceService.getAllContactsWithGeo();
var promises = [];
promises.push(currentPosition);
promises.push(allContacts);
promises.push(restaurantModal);
var allMarkers = [];
var allContactDetails = [];
currentPosition.then(
function(position) {
console.log('position data -->', position);
var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var mapOptions = {
center: latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
$scope.map = new google.maps.Map(document.getElementById("map"), mapOptions);
var bounds = new google.maps.LatLngBounds();
allContacts.then(
function(contacts) {
console.log('contacts final -->', contacts);
for (var i=0; i<contacts.records.length; i++) {
var contact = contacts.records[i];
console.log('single contact -->', contact.MailingLatitude, contact.MailingLongitude);
var contactlatLng = new google.maps.LatLng(contact.MailingLatitude, contact.MailingLongitude);
var contactInfo = {};
//contactInfo.marker = {};
var marker = new google.maps.Marker({
map: $scope.map,
animation: google.maps.Animation.DROP,
position: contactlatLng
});
contactInfo.marker = marker;
contactInfo.recordDetails = contact;
allMarkers.push(marker);
allContactDetails.push(contactInfo);
// Set boundary for markers in map
bounds.extend(contactlatLng);
}
// Fit map based on markers
$scope.map.fitBounds(bounds);
}
);
// google.maps.event.addListenerOnce($scope.map, 'idle', function(){
// });
},
function(error) {
console.log("Could not get location" + error);
}
);
// Add listener for marker pop up once all promises resolved
$q.all(promises).then(
function(values) {
console.log('first -->', values[0]);
console.log('second -->', values[1]);
console.log('third -->', values[2]);
var detailModal = values[2];
$scope.modal = detailModal;
for (var i=0; i<allContactDetails.length; i++) {
allContactDetails[i].marker.addListener('click', function() {
console.log('helllos from marker');
console.log('all contactInfo -->', allContactDetails[i].recordDetails.Name);
$scope.contactName = allContactDetails[i].recordDetails.Name;
detailModal.show();
});
}
}
);
})
Front end template code -
<script id="templates/bottom-sheet.html" type="text/ng-template">
<ion-bottom-sheet-view>
<ion-header-bar align-title="left">
<h1 class="title">New Particle</h1>
<button class="button button-icon icon ion-android-close" ng-click="modal.hide()"></button>
{{contactName}}
</ion-header-bar>
</ion-bottom-sheet-view>
</script>
Now the modal opens properly when i click on the google marker, but I am not sure how to pass dynamic data to the pop modal.
Since you are doing this :
var restaurantModal = $ionicModal.fromTemplateUrl('templates/bottom-sheet.html', {
scope: $scope,
viewType: 'bottom-sheet',
animation: 'slide-in-up'
});
Your modal can access to the scope of your controller.
So if you declare any variable in your controller it will be accessible through the modal.
viewtest is bound to a JSONModel. View2 is bound to the same JSONModel by creating a reference to viewtest and setting the model to viewtest.getModel().
What I'm trying to do is modify the shared model data in View3 by clicking a button so that the texts in textfield and textview will change automatically. However, the texts in textfield and textview remain "This is a text". What's the problem?
The index.html file:
and the viewtest.view.js file:
sap.ui.jsview("viewtest.viewtest", {
getControllerName : function() {
return "viewtest.viewtest";
},
createContent : function(oController) {
this.setModel(new sap.ui.model.json.JSONModel());
var oData = {
text: "this is a text"
};
this.getModel().setData(oData);
var oTextField = new sap.ui.commons.TextField({value: "{/text}"});
return [oTextField];
}
});
View2.view.js file:
sap.ui.jsview("viewtest.View2", {
getControllerName : function() {
return "viewtest.View2";
},
createContent : function(oController) {
var viewtest = sap.ui.view({viewName: "viewtest.viewtest", type:sap.ui.core.mvc.ViewType.JS});
this.setModel(viewtest.getModel());
this.getModel().setData(viewtest.getModel().getData());
var oTextView = new sap.ui.commons.TextView({text: "{/text}"});
return [oTextView];
}
});
View3.view.js file:
sap.ui.jsview("viewtest.View3", {
getControllerName : function() {
return "viewtest.View3";
},
createContent : function(oController) {
var oButton = new sap.ui.commons.Button({text:"click", press: func});
function func() {
var oView = new sap.ui.view({viewName:"viewtest.viewtest", type:sap.ui.core.mvc.ViewType.JS});
oView.getModel().setData({text:"hello world"}, true);
}
return [oButton];
}
});
Just a suggestion. Maybe it is worth to give in your .html file id to every view, and then in view3 update and set model to each one of the views by calling them by id?
Like,
in index.html:
var view1 = new sap.ui.view({id:"view1", viewName:"viewtest.View1", type:sap.ui.core.mvc.ViewType.JS});
and then in view3:
function func() {
var oView = sap.ui.getCore().byId("view1");
oView.getModel().setData({text:"hello world"}, true);
oView.getModel().refresh(); //if setting new model won't update the views
}
Or, if you use the same model in all your views, set model not to each view separately, but to the core:
viewtest.view.js file:
sap.ui.getCore().setModel(new sap.ui.model.json.JSONModel());
thus, you don't need to set model in view2.