I'm trying to format gender field (in SAP table field: CHAR1 to 0(F) and 1(M) to fit the selectedIndex property of RadioButtonGroup.
This is my view : (DetailDialog.fragment.xml )
<RadioButtonGroup width="100%" columns="2" selectedIndex="{path: 'Gendr', formatter:'.formatter' }" id="__group1">
The above XML Fragment is called by the main view controller:
ItemPress: function(oEvent) {
var detailDialog = this.getView().byId("DetailDialog");
var that = this;
var view = this.getView();
var path = oEvent.getParameter("listItem").getBindingContext().getPath();
var oDummyController = {
formatter: function(gendr) {
switch (gendr) {
case "M":
return 0;
case "F":
return 1;
}
},
closeDialog: function() {
detailDialog.close();
}
};
if (!detailDialog) {
detailDialog = sap.ui.xmlfragment(view.getId(), "Demo1.view.DetailDialog", oDummyController);
}
var jSonModel = new sap.ui.model.json.JSONModel();
function fnSuccess(oData, oResponse) {
jSonModel.setData(oData);
}
var oModel = view.getModel();
oModel.read(path, {
success: fnSuccess
})
//Set data for dialog
this.getView().byId("__formDetail").setModel(jSonModel);
detailDialog.open();
}
My problem is that the formatter is not working at all.
Any suggestion?
Option one: (not sure if it works for fragments too)
Change formatter:'.formatter' to formatter:'Demo1.view.DetailDialog.formatter'.
Option two: Format the data since anyway you are binding data from controller. (And surely will work.)
function fnSuccess(oData, oResponse) {
oData.GendrValue = oData.Gendr == "M"?1:0;
jSonModel.setData(oData);
}
and also change the binding: selectedIndex="{path: 'GendrValue'}"
Related
I wish to generate a custom dropdown filter, based on categories from a database.
How is this achieved?
In my example, this is (poorly) implemented with some hard coding and duplication.
var serviceOverlays = [
{name:"Cardiology", value:"cardiology"},
{name:"Opthamology", value:"opthamology"}
];
var oSelect = L.control({position : 'topright'});
oSelect.onAdd = function (map) {
var overlayParent = document.getElementById('new-parent'); // overlays div
var node = L.DomUtil.create('select', 'leaflet-control');
node.innerHTML = '<option value="cardiologist">Cardioligist</option><option value="opthamology">Opthamology</option>';
overlayParent.appendChild(node);
L.DomEvent.disableClickPropagation(node);
L.DomEvent.on(node,'change',function(e){
var select = e.target;
for(var name in serviceOverlays){
serviceOverlays[name].removeFrom(map);
}
serviceOverlays[select.value].addTo(map);
});
Fiddle
I created a Control for you:
L.Control.Select = L.Control.extend({
options: {
position : 'topright'
},
initialize(layers,options) {
L.setOptions(this,options);
this.layers = layers;
},
onAdd(map) {
this.overlayParent = L.DomUtil.create('div', 'leaflet-control select-control');
this.node = L.DomUtil.create('select', 'leaflet-control',this.overlayParent);
L.DomEvent.disableClickPropagation(this.node);
this.updateSelectOptions();
L.DomEvent.on(this.node,'change',(e)=>{
var select = e.target;
for(var value in this.layers){
this.layers[value].layer.removeFrom(map);
}
this.layers[select.value].layer.addTo(map);
});
return this.overlayParent;
},
updateSelectOptions(){
var options = "";
if(this.layers){
for(var value in this.layers){
var layer = this.layers[value];
options += '<option value="'+value+'">'+layer.name+'</option>';
}
}
this.node.innerHTML = options;
},
changeLayerData(layers){
this.layers = layers;
this.updateSelectOptions();
}
});
var oSelect = new L.Control.Select(serviceOverlays,{position : 'topright'}).addTo(map);
The data structure have to be:
var serviceOverlays = {
"cardiology": {name:"Cardiology", layer: cities},
"opthamology": {name:"Opthamology", layer: badCities}
};
Demo: https://jsfiddle.net/falkedesign/1rLntbo5/
You can also change the data dynamicl< with oSelect.changeLayerData(serviceOverlays2)
Once I click on particular row of a table it should display the details in a dialog.
Here is my code...
onMessageDialogPress: function (oEvent) {
var oSelectedItem = oEvent.getSource().getParent();
var oBindingContext = oSelectedItem.getBindingContext();
if (!this._oDialog){
this._oDialog = sap.ui.xmlfragment("mycompany.app.MyMasterDetailApp.view.Dialog", this);
}
this._oDialog.setBindingContext(oBindingContext);
this._oDialog.open();
}
my problem is solved. I did small changes and now it is working as expected.
This is the working code.
onMessageDialogPress: function (oEvent) {
var oSelectedItem = oEvent.getSource();
var oBindingContext = oSelectedItem.getBindingContext();
if (!this._oDialog){
this._oDialog = sap.ui.xmlfragment("mycompany.app.MyMasterDetailApp.view.Dialog", this);
}
this._oDialog.setBindingContext(oBindingContext);
this.getView().addDependent(this._oDialog);
this._oDialog.open();
},
Thanks
Is there a way to add an icon/img before the input checkbox inside the layer control?
And is there a way to add a value(or id) prop to the checkbox?
For now I can add an icon with this, but that is not exacltly what I want. Thanks.
L.control.layers({
null
}, {
'<img src="/img/fish.png">Some text':new L.layerGroup(),
}).addTo(map);
This will add an img after the checkbox. Maybe somehow override the _addItem method in the Control.Layers.js, but I don't know how.
Update: Is there a way to add a value prop to the checkbox on this stage?
var layers = L.control.layers({}, {
'name':new L.layerGroup(), // how to add val?
}).addTo(map);
So I can add a value and name(span, label) to the checkbox to get the
<div>
<input type="checkbox" value="some val" class="leaflet-control-layers-selector"><span>name</span>
</div>
Might want to do this with custom JavaScript. I don't believe there is any built-in way to accomplish this. Try something like this:
Save the control layers to a variable:
var layers = L.control.layers({}, {'name' : new L.layerGroup()}).addTo(map);
Get the _overlaysList property (unless you're altering a base map):
var list = layers._overlaysList;
Iterate the input tags:
var inputs = list.getElementsByTagName('input');
Find the one you want to alter, and prepend an image to it.
Well, here is my solution, if someone is interested
//---------------- OVERRIDING THE LAYERS -------------------
L.Control.IconLayers = L.Control.Layers.extend({
initialize: function (baseLayers, overlays, options) {
L.Control.Layers.prototype.initialize.call(this, baseLayers, overlays, options);
},
_addItem: function (obj) {
//console.log("Layer Control:",obj)
var label = document.createElement('label'),
input, icon = false,
checked = this._map.hasLayer(obj.layer);
if (obj.overlay) {
input = document.createElement('input');
input.type = 'checkbox';
input.className = 'leaflet-control-layers-selector';
input.defaultChecked = checked;
input.value = obj.name; // add
console.log(obj)
if ('getIcon' in obj.layer) {
icon = obj.layer.getIcon();
}
} else {
input = this._createRadioElement('leaflet-base-layers', checked);
}
var layer_name = obj.name
if (obj.layer.hasOwnProperty('_options')){
layer_name = obj.layer._options.name
input.id = obj.layer._options.id
}
input.layerId = L.stamp(obj.layer);
L.DomEvent.on(input, 'click', this._onInputClick, this);
var name = document.createElement('span');
name.innerHTML = ' ' + layer_name;
label.appendChild(input);
if (icon) {
var i = document.createElement('span');
i.innerHTML = icon;
label.appendChild(i);
}
label.appendChild(name);
var container = obj.overlay ? this._overlaysList : this._baseLayersList;
container.appendChild(label);
return label;
}
});
L.control.iconLayers = function(baseLayers, overlays, options) {
return new L.Control.IconLayers(baseLayers, overlays, options);
}
L.customLayerGroup = L.LayerGroup.extend({
initialize: function (layers) {
console.log("LAYERS:",layers)
L.LayerGroup.prototype.initialize.call(this, layers);
this._options = layers;
},
});
//---------------- OVERRIDING THE LAYERS -------------------
var layers = L.control.iconLayers({
'Mapbox Streets': L.mapbox.tileLayer('mapbox.streets').addTo(map),
'Mapbox Light': L.mapbox.tileLayer('mapbox.light')
}, {
'1':new L.layerGroup(),
'2':new L.layerGroup(),
'3':new L.customLayerGroup({name:"Boats",id:"3", value:"3"}),
}).addTo(map);
Hi I'm trying to filter an observable array of data fetched via a HTTP request on keypress of the SearchBar.
I managed to get the SearchBar property change to work but I can't seem to figure out what I'm doing wrong in the filtering logic.
Ideally I want to update the list as I type in the search term in the SearchBar. I've searched the API on the Telerik site, there wasn't really any examples I could find.
XML
<Page loaded="pageLoaded">
<ActivityIndicator busy="{{ isLoading }}" />
<ActionBar title="People">
</ActionBar>
<GridLayout>
<StackLayout>
<SearchBar id="searchBar" hint="Search for someone"></SearchBar>
<ListView items="{{ peopleList }}" itemTap="showDetail">
<ListView.itemTemplate>
<StackLayout>
<Label text="{{ fullName }}" horiztonalAlignment="left" verticalAlignment="center"></Label>
<Label text="{{ company }}" class="info"></Label>
</StackLayout>
</ListView.itemTemplate>
</ListView>
</StackLayout>
</GridLayout>
</Page>
JS
var frames = require("ui/frame");
var Observable = require("data/observable").Observable;
var PeopleListViewModel = require("../../shared/people-viewModel");
var activityIndicatorModule = require("ui/activity-indicator");
var page;
var userkey;
var peopleList = new PeopleListViewModel([]);
var pageData = new Observable({ peopleList: peopleList });
exports.pageLoaded = function(args) {
page = args.object;
page.bindingContext = pageData;
userkey = userkey || page.navigationContext.userkey;
peopleList.load(userkey); // fetch data from the backend
var searchBar = page.getViewById("searchBar");
searchBar.on("propertyChange", function (args) {
var searchText = args.object.text;
if (searchText === "") {
// NOT SURE WHAT TO DO HERE.
} else {
peopleList.filter(function (element, index, array) {
// DOESN"T WORK PROPERLY
console.log("element: ", JSON.stringify(element));
return element.fullName == searchText;
});
console.log("Text types: ", searchText);
}
});
};
exports.showDetail = function(args) {
var person = peopleList.getItem(args.index);
var navigateEntry = {
moduleName: "views/people/people-detail",
context: { person: person },
animated: false
};
frames.topmost().navigate(navigateEntry);
};
PeopleListViewModel.js
var config = require("./config");
var fetchModule = require("fetch");
var ObservableArray = require("data/observable-array").ObservableArray;
function PeopleListViewModel(people) {
var viewModel = new ObservableArray(people);
viewModel.load = function (userKey) {
return fetchModule.fetch(config.baseUrl + "/api/people/all/" + userKey)
.then(function (response) {
return response.json();
})
.then(function (data) {
data.forEach(function (person) {
viewModel.push(person);
});
}, function (error) {
console.log("Error: ", error);
});
};
viewModel.empty = function () {
while (viewModel.length) {
viewModel.pop();
}
};
return viewModel;
}
function handleErrors(response) {
if (!response.ok) {
console.log("Error occurred");
}
}
module.exports = PeopleListViewModel;
Updated people-list
var frames = require("ui/frame");
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var PeopleListViewModel = require("../../shared/people-viewModel");
var activityIndicatorModule = require("ui/activity-indicator");
var page;
var userkey;
var peopleList = new PeopleListViewModel([]);
var pageData = new Observable({ peopleList: peopleList });
var resultList = new ObservableArray([]);
exports.pageLoaded = function(args) {
page = args.object;
page.bindingContext = pageData;
userkey = userkey || page.navigationContext.userkey;
peopleList.load(userkey);
var searchBar = page.getViewById("searchBar");
searchBar.on("propertyChange", function (args) {
var searchText = args.object.text;
if (searchText === "") {
} else {
while (resultList.length > 0) {
resultList.pop();
}
peopleList.forEach(function (element) {
if (element.fullName === searchText) {
resultList.push(element);
}
});
}
});
};
I had the same issue. If you want to filter your data after every character has changed in search-bar you can try my solution.
Definitions
My playerList is your peopleList. This is the data from view-model.
resultList is an array where the data will be pushed.
var observableArrayModule = require("data/observable-array").ObservableArray;
var playerList = new PlayerListViewModel([]);
var resultList = new observableArrayModule([]);
var pageData = new observableModule.Observable({
resultList: resultList,
player: ""
});
Inside expors.loaded()
page = args.object;
searchBar = page.getViewById("search-bar");
page.bindingContext = pageData;
Load Initial Data - inside expors.loaded()
We are loading initial data when user navigates to the screen for the first time. We are also pushing the same data to resultList since we are using {{resultList}} in xml. You can add loadingIndicator while the list is populated.
playerList
.load()
.then(function() {
setTimeout(function() {
playerList.forEach(function (element) {
pageData.resultList.push(element);
});
}, 1000);
})
.catch(function(error) {
dialogsModule.alert({
message: "An error occurred while loading players.",
okButtonText: "OK"
});
});
Clear autofocus - inside expors.loaded()
This is to prevent keyboard from opening on initial screen navigation.
if (searchBar.ios) {
searchBar.ios.endEditing(true);
} else if (searchBar.android) {
searchBar.android.clearFocus();
}
Search data when character has changed - inside expors.loaded()
I am calling filter functionality. Lodash _.debounce function is used to delay looping through resultList array. Without it, the app would loop every time letter is typed. Now we are waiting for user to stop typing to start looping.
searchBar.on('propertyChange', _.debounce(searchList, 500));
searchList Function
This is the actual loop. You can change element.name for your needs.
function searchList(args) {
var searchText = args.object.text;
while(resultList.length > 0) {
resultList.pop();
}
playerList.forEach(function (element) {
if (element.name.toLowerCase().indexOf(searchText) >= 0) {
resultList.push(element);
}
});
}
Hide keyboard if search-bar is cleared - inside exports.loaded()
And finally we want to hide the keyboard if user clears the search-bar.
searchBar.on(searchBarModule.SearchBar.clearEvent, function (args) {
setTimeout(function() {
searchBar.dismissSoftInput();
}, 10);
});
PS
You probably solved your issue, but this could help someone else in the future.
Okay so your problem is a Javascript problem than a NativeScript problem. For the sake of this problem, think of observable arrays as just your ordinary arrays.
In your JS you're creating a new PeopleListViewModel which you're then attaching to the bindingContext via the pageData object. So far so good. Then you're calling the load method on the PeopleListViewModel (It returns a promise which you're not really doing anything with but for this specific problem it doesn't matter).
However, when text is inputed you're not really doing anything. This is your code:
peopleList.filter(function (element, index, array) {
// DOESN"T WORK PROPERLY
console.log("element: ", JSON.stringify(element));
return element.fullName == searchText;
});
peopleList is an instance of PeopleListViewModel which returns an ObservableArray. The ObservableArray does indeed have a method called filter (which works just like filter of a regular array. Check out the NativeScript documentation and Javascript documentation of filter).
What you need to understand here is that filter returns a new array with the filtered results. Doing peopleList.filter() will send that new array into empty space. You want to var yourNewFilteredArray = peopleList.filter(). But you don't really want to redefine the array bound to the binding context, you want to modify the content of it.
Here's an example of how you could do that:
/*
* Attach a new obsersable array to the binding context.
* you can prepopulate it with the data from the
* PeopleListViewModel if you want to
*/
var resultList = new ObservableArray([]);
var pageData = new Observable({ resultList: resultList });
/*
* Then on search/filter you want to modify this new
* array. Here I first remove every item in it and then
* push matching items to it.
*/
searchBar.on("propertyChange", function (args) {
var searchText = args.object.text;
// ...
while(resultList.length > 0) {
resultList.pop();
}
peopleList.forEach(function (element) {
if (element.fullName === searchText) {
resultList.push(element);
}
});
});
I am trying to pass input value from one view to another like this
Firstview
oFooter.addContent(new sap.m.Button("b1", {
text : "Execute",
icon : "sap-icon://display",
styled : false,
press : function() {
var In_obj = sap.ui.getCore().byId('inobj').getValue();
var Ins_obj = sap.ui.getCore().byId('insobj').getValue();
var In_exid = sap.ui.getCore().byId('exid').getValue();
var In_dp1 = sap.ui.getCore().byId('DP1').getValue();
var In_dp2 = sap.ui.getCore().byId('DP2').getValue();
var In_usr = sap.ui.getCore().byId('User').getValue();
var In_tcd = sap.ui.getCore().byId('tcode').getValue();
var In_prg = sap.ui.getCore().byId('prog').getValue();
app.to("page2", {
Input_obj : In_obj,
Input_sobj : Ins_obj,
Input_exid : In_exid,
Input_dp1 : In_dp1,
Input_dp2 : In_dp2,
Input_usr : In_usr,
Input_tcd : In_tcd,
Input_prg : In_prg,
});
}
}));
Secondview.controller.js
onInit : function() {
alert("second page init" );
view.addEventDelegate({
onBeforeShow: function(evt) {
var idToRetrieve = evt.data.Input_obj;
Input_obj = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_sobj;
Input_sobj = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_exid;
Input_exid = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_dp1;
Input_dp1 = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_dp2;
Input_dp2 = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_usr;
Input_usr = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_tcd;
Input_tcd = idToRetrieve.getValue();
var idToRetrieve = evt.data.Input_prg;
Input_prg = idToRetrieve.getValue();
alert( Input_obj );
console.log( Input_obj);
}});
},
Now, I don't know how to use variables (Input_obj, Input_sobj, ...) in Secondview.js(view). Can I have some guidance about this ?
As far as i can see in your code idToRetrieve should have the value(text) of the the element with ID inobj.
You are passing the dataobj while calling the app.to method and therefore in the onbeforeshow method the data should be available.
There is a concept of routes in SAPUI5 specifically which can also be used here
Routing
But with the current approach as well i can see the data should be available in the onbeforeshow method
For Example
app.to("detailPage", {id:"42"}); // trigger navigation and hand over a data object
// this data object could also be a binding context when dealing with data binding
...
// and where the detail page is implemented:
myDetailPage.addEventDelegate({
onBeforeShow: function(evt) {
var idToRetrieve = evt.data.id;
// ...now retrieve the data element with the given ID and update the page UI
}
});