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.
Related
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.
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.
I use KendoUI grid with popup edit mode. After applying filter to any column it is not possible to add new object correctly. Pressing Add button many times does not show edit popup. But after clearing the filter empty objects are shown in the grid.
Is there any workaround?
I found a workaround. Instead of standard Add button use toolbar template in which add link "Add" with custom handler triggering grid add. In that handler check if filtering is used on grid and if so store current filtering to a var and remove filtering. Also bind to grid "save" and "cancel" events handlers which will apply previous filtering after adding new object (or cancelling).
<kendo:grid-toolbarTemplate>
<div>
<a class="k-button k-button-icontext" onclick="addItemHandler()">Add</a>
...
var gridFilter;
function addItemHandler() {
var table = $("#myGrid").data("kendoGrid");
gridFilter = table.dataSource.filter();
if (gridFilter) {
table.dataSource.filter(null);
}
table.addRow();
}
function gridSavedHandler(e) {
restoreFilter(e.sender);
}
function gridEditCanceledHandler(e) {
e.preventDefault();
e.sender.cancelChanges();
restoreFilter(e.sender);
}
function restoreFilter(table) {
if (gridFilter) {
table.dataSource.filter(gridFilter);
gridFilter = null;
}
}
$(document).ready(pageInitHandler);
function pageInitHandler() {
var table = $("#myGrid").data("kendoGrid");
table.bind("save", gridSavedHandler);
table.bind("cancel", gridEditCanceledHandler);
}
Workaround is complicated one but really works.
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
I have a dynamic HTML table, where I can add and remove rows.
Each row contains a button that has a class removeRow.
In my JavaScript, I have:
$('button.removeRow').live("click", function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
The problem is that it works for all buttons that belong to rows that were inserted after the page was loaded (by clicking on 'Add row' button).
It works for existing buttons, only if I change the above code to (but then it does not work for dynamically added rows):
$('button.removeRow').click(function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
I think that the live function should work for both, so can you point me into the right direction? Where can it go wrong?
OK I found a bug today. Somewhere in my code I had:
$('input[type=submit], button').click(function () {
return false;
});
I wanted it to work with the submit button, so it would not submit the form on click. I do not remember why I put button there. Anyways, because of that my static button clicks were attached this event, while dynamically created ones were not. Therefore live 'click' worked for dynamic buttons. Stupid mistake...
Hacky solution: Do both
$('button.removeRow').live("click", function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
and
$('button.removeRow').click(function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
It would be helpful if you posted some example HTML as well as the code responsible for inserting new rows, though.
Maybe something is going wrong if other tr elements are matched by your .parents() selector. Try .closest():
$('button.removeRow').live("click", function(){
$(this).closest('tr').remove();
return false;
});
The live should work for both dynamic and pre-rendered elements.
I'd start by working out if that content really exists before that jQuery is run...Try outputting the result of the following somewhere, or use the debugger keyword, or even the dreaded alert:
$('button.removeRow').length
// The rest of your click handler definition...