In w2ui I can map a json to a sidebar http://w2ui.com/web/demos/#!sidebar/sidebar-1
Can I do it in openui5?
I want the same result.
Obviously I do not want a tree but a list of items that swipe right if I tap on an item (and visualize a sub-menu list) and slide left if I press back button (and visualize the menu at upper level).
I think it's possible, but as far as I know you have to do some manual labor:
Detect whether your node has one or more child nodes, and based on that set the sap.m.ListType to Navigation or not
If your root node (f.i., "/items") has child nodes (f.i., "childs"), you need to re-bind your list to this child path ("/items/<index_of_parent_node>/childs)
To get the swiping effect, you probably need to encapsulate the list in a sap.m.Page
Depending on the node level you're in, you need to hide/display your back button, and by pressing it bind your list to the parent path
However, if there's a cleaner, simpler approach I would love to hear it too!
I solved my problem:
Every time that i click on a menu item i call this function into view controller:
//when click on item
onPressMenuItem: function(evt) {
var selectedItem=evt.getSource().getBindingContext().getObject();
var objAction=getActionWhenPressMenuItem(selectedItem, this.getView().getModel());
console.log(objAction);
if(objAction.hasNextSidebar==true){ // sub menu
var model = new sap.ui.model.json.JSONModel();
model.setData(objAction.nextSidebar);
var oSplitApp=sap.ui.core.Core().byId("splitApp");
var nextView = sap.ui.xmlview("general.master.menuMaster");
nextView.setModel(model);
nextView.byId("idPageSidebar").setTitle(selectedItem.text);
oSplitApp.addMasterPage(nextView);
oSplitApp.toMaster(nextView);
}else{ // open operation detail
var idDetail =objAction.opDetail;
var targetApp = getAppBySelectionId(idDetail);
if(targetApp.masterView!=null){//if app has own master
sap.ui.getCore().getEventBus().publish("navMaster", "to", {
idView: targetApp.masterView
});
}
if(targetApp.detailView!=null){//if app has own detail
sap.ui.getCore().getEventBus().publish("navDetail", "to", {
//titleOfDetailPage: selectedItem.text,
idView: targetApp.detailView,
//idCall: selectedItem
});
}
}
},
I create every time a new istance of the menu on a new page.
Related
In google chrome in history section, I want to delete all the histories related to a specific website for example: facebook.com, I can search facebook.com and then select all checkboxes and delete but its a time-consuming work.
Is there any easy way to clear the history of specific websites?
even by writing code or script?
open the history manager, search for facebook.com... do not click all the checkboxes individually. Click the first box, scroll to the bottom of the page and hold shift while clicking the last box, it will select all of them at once.
protip: if you want to visit a website without leaving a history entry, go into incognito mode (control-shift-p).
or, Control-A keyboard shortcut will select all of the checkboxes as well! https://techdows.com/2018/02/chrome-history-page-ctrl-a-now-selects-all-history-items.html#:~:text=Chrome%20history%20Page%3A%20Ctrl%2BA%20now%20selects%20all%20items&text=Now%20the%20addition%20of%20Ctrl,or%20unselect%20multiple%20history%20items.&text=The%20thing%20is%2C%20only%20150,page%20has%20more%20history%20items.
You can use some scripting in the console to click checkboxes for entries with hrefs containing a substring.
This answer uses this other SO answer on a querySelectorAll that works for things inside open shadow DOMs:
function $$$(selector, rootNode=document.body) {
const arr = []
const traverser = node => {
// 1. decline all nodes that are not elements
if(node.nodeType !== Node.ELEMENT_NODE) {
return
}
// 2. add the node to the array, if it matches the selector
if(node.matches(selector)) {
arr.push(node)
}
// 3. loop through the children
const children = node.children
if (children.length) {
for(const child of children) {
traverser(child)
}
}
// 4. check for shadow DOM, and loop through it's children
const shadowRoot = node.shadowRoot
if (shadowRoot) {
const shadowChildren = shadowRoot.children
for(const shadowChild of shadowChildren) {
traverser(shadowChild)
}
}
}
traverser(rootNode)
return arr
}
arr = $$$('[href*="example.com"]');
// this code will need to be updated if the source code for the chrome history browser changes.
arr.map(e => e.closest("#item-info")
.previousElementSibling
.previousElementSibling
).forEach(e=>e.click());
This will click all the matching entries on the current page, and then you can just click the button to delete the checked entries.
I have data for a list that is coming from an apollo query. The query fetches all of the data and the ul is used to display the list. Ideally, I have a button that adds a new item to the end of the list and once that button is pressed and the new item added, I want to scroll to the item on the list. My code is as follows.
const { data } = useQuery(getData);
<ul id="itemList">
{data.map(item=> <li key={item.id} id={item.id}>{item.title}</li> )
</ul>
Somewhere else on the page, I have a button you can click to use the apollo mutation hook which adds a new item to the list and refetches the getData query.
const [createListItem, { loading, error }] = useMutation(createItem);
const resp = await createListItem({variables: {details: {title: "New Item"}}, refetchQueries: [{query: getData}]
I assumed once this was done and the item is added to the list (which I can see visibly), I can use the following code below to scroll to the item on my list programitically. Id is automatically added by my DB once this item is added to the backend DB (MongoDB).
const listItem = document.getElementById(resp.data.createListItem.id);
listItem?.scrollIntoView({ behavior: "smooth" });
The listItem variable shows null. This is most likely due to the DOM not refreshing before I try to scroll to the item. If I hardcode an id that already exists (besides my newly created one), the auto scroll works.
How can I get the li document for the newly created item once added and query refetches and then scroll to it? Is there an "onchange" event or something like that I can listen for using addEventListener to search for my newly created item on the list and then scroll to it?
Thanks
I figured it out. Thanks for the componentDidUpdate suggestion. I did this using React Hooks (useEffect and useState) .
To reference my original question above, once I add the item using the mutation hook, I store the id of the newly added item in state
const [addedItem, updateAddedItem] = useState("")
So to reference code in question above.
const resp = await createListItem({variables: {details: {title: "New Item"}}, refetchQueries: [{query: getData}]
updateAddedItem(resp.data.createListItem.id)
In the component where I am rendering my list, I use the useEffect hook.
useEffect(() => {
const listItem = document.getElementById(addedItem);
listItem?.scrollIntoView({ behavior: "smooth" });
}
}
}, [data]);
This way, when the data is updated, the list item is available in the DOM to scroll to.
I have a controller named dataController, two services, named dataHttpServices and dataLocalServices and an html template, some directives.
In my html template, I have two different tabs uses same controller and add item to list in my controller from two different places.
In debug mode, I see the data change properly but the data binding is not working properly.
I don't know What is my mistake, help please. In code;
Here is Html;
<div
class="metadataSelect"
layout="column"
ng-model="selectedItems"
ng-show="selectedItems.length > 0">
<div layout="row" ng-repeat="item in selectedItems">
{{item.Name}}
</div>
</div>
Here is the controller;
$scope.addSelectedItem = function (selectedItem) {
var found = false;
var self = this;
dataLocalService.addSelectedItem(selectedItem);
$scope.selectedItems = dataLocalService.getSelectedItems();
};
And here is the service;
this.selectedItems = [];
this.addSelectedItem = function (item) {
this.selectedItems.push(item);
};
this.getSelectedItems = function () {
return this.selectedItems;
};
I call addSelectedItem from scope in two different button's click event with ng-click.
If I first add an item by click the first button and click the second button (first click the first button), the button binds the array to div correctly.
But when I add an item by click the second button before click the first button, the array does not bind to div.
After add some items to array by click the second button, when I click the first button, bind all the elements to div. For example three element at once but doesn't bind without clicking the first button.
What is my mistakes. Thanks for helps.
I solved it with using $scope.$watch. And I think the problem is their scope is different because i create controller twice with ng-controller. Here is the code snippet i found to solve it.
$scope.$watch('selectedItems', function () {
$scope.selectedItems = $metadataLocalService.getSelectedItems();
});
This solves my problem. Because watch is tracking the related data changes and etc.
I have a list of courses in rows like this:
Whenever I click a row, a new tab is created, and a new window is added to that tab showing the course info.
Then if I press back, it goes back to the courses window, which is great, but when I click another course it adds that to the list of tabs, so it starts looking like this:
Whereas, there should only be two tabs here, the Courses tab and Get Courses tab.
In get_courses.js (the file that deals with making the rows) I have this event listener which creates a new tab every time a row is clicked (which I'm sure is where my mistake is, I'm just not sure how to fix it):
table.addEventListener("click",function(e){
var courseInfo_window = Titanium.UI.createWindow({
title:e.rowData.title,
url:'get_courseInfo.js',
courseIMISCode: e.rowData.courseIMISCode
});
var courseInfo_tab = Titanium.UI.createTab({
title:'Course Info',
window:courseInfo_window
});
Titanium.UI.currentTabGroup.addTab(courseInfo_tab);
});
Which I want to be there to create a Course Info tab, but then in get_courseInfo.js I have this, possibly redundant code:
Ti.UI.currentTabGroup.activeTab.open(courseInfo_window);
Which, in my noob mind seems necessary to open my courseInfo_window, but is accumulating the tabs in the bottom (as shown in the image earlier).
TL;DR: What do I need to do (probably in get_courses.js) to update the Course Info tab instead of opening a new tab for each row click?
You can access tabs in TabGroup through tabs property. However, it would be easier to keep reference to tab which you created outside of event listener and modify inside:
var courseInfo_tab = null;
table.addEventListener("click",function(e){
var courseInfo_window = Titanium.UI.createWindow({
title:e.rowData.title,
url:'get_courseInfo.js',
courseIMISCode: e.rowData.courseIMISCode
});
if (courseInfo_tab === null) {
courseInfo_tab = Titanium.UI.createTab({
title:'Course Info',
window:courseInfo_window
});
Titanium.UI.currentTabGroup.addTab(courseInfo_tab);
} else {
courseInfo_tab.window = courseInfo_window;
}
});
I'm trying to drag Ember objects from one list to another. If I drag an item to a new list, the item should be removed from its current list and moved to the new one.
Thanks to Drag&Drop with Ember.js and Ember.js - drag and drop list, I figured out how to copy an item to a different list. However, I am unable to determine from which list a dragged object originated. I have dozens of lists on the page, so I'd rather not do a O(n*k) search for the original object.
Currently, I'm using Ember views and the HTML 5 API. It seems like the Handelbars action helper should achieve my goal more easily. Ember's action supports the drop event, but I can't get it to fire: {{ action foo on="drop" }}. It probably has something to do with the nuanced event propagation defaults of the HTML 5 drag-and-drop implementation.
If you know how to solve this problem using actions instead of views, I'd much prefer that solution.
Here's how I'm currently transferring objects:
// this is heavily inspired by http://jsfiddle.net/ud3323/5uX9H/
// Draggable items
App.ItemView = Ember.View.extend({
templateName: 'item',
attributeBindings: 'draggable',
draggable: 'true',
dragStart: function(event) {
var dataTransfer = event.originalEvent.dataTransfer;
// The view's context is the item to transfer
var item = this.get('context');
// Use HTML 5 API to transfer object as JSON.
// There must be a more elegant way to do this.
dataTransfer.setData('application/json', JSON.stringify(item));
}
});
// Item list drop zone
App.ItemListView = Ember.View.extend({
templateName: 'itemList',
dragEnter: function(event) {
event.preventDefault();
return false;
},
dragOver: function(event) {
event.preventDefault();
return false;
},
drop: function(event) {
event.preventDefault();
// Extract the transferred data
var rawData = event.dataTransfer.getData('application/json');
// Create a new Ember object from the data
var item = App.Todo.create(JSON.parse(rawData));
this.get('controller').send('add', item);
return false;
}
});
Check out JS Bin for the complete code.
Thanks in advance for your help. Very much appreciated.
This is maybe not the full solution to your problem, but it satisfies the need to use the action helper instead of the itemView. Here is your modified jsbin http://jsbin.com/ibufeh/15/edit?html,javascript,live, the drop event fires and is catched at the ApplicationRoute level, from where you can then redirect your function call to the appropriate controller, have a look! it's not working correctly but it solves part of your problem - using an action helper. You need still to figure out from which list the item originated, but this will be easy I guess.
hope it helps