I'm using angular-ui-tree for building a tree of items in my app.
I'm using its drag & drop feature and I need to know when & where (on what element) the dropping occurs.
For example, I drag item1, and drop it on a panel. I want the panel to display the item name. (each item has a name property). the panel is just a simple div with text inside.
I saw in the documentations that I can access the "dropped" event in my controller. But I don't understand how to change the panel content according to the dragged & dropped item.
As in documentations $callbacks (type: Object)
$callbacks is a very important property for angular-ui-tree. When some
special events trigger, the functions in $callbacks are called. The
callbacks can be passed through the directive.
you define the events in a treeOptions collection
myAppModule.controller('MyController', function($scope) {
// here you define the events in a treeOptions collection
$scope.treeOptions = {
accept: function(sourceNodeScope, destNodesScope, destIndex) {
return true;
},
dropped: function(e) {
console.log (e.source.nodeScope.$modelValue);
}
};
});
then in your tree div add callbacks="treeOptions" which you defined above in the controller
<div ui-tree callbacks="treeOptions">
<ol ui-tree-nodes ng-model="nodes">
<li ng-repeat="node in nodes" ui-tree-node>{{node.title}}</li>
</ol>
</div>
then you can access the old parent from here
e.source.nodeScope.$parentNodeScope.$modelValue
and you can access the new parent from here
e.dest.nodesScope.$parent.$modelValue
Hey guys i just found it !
$scope.treeOptions = {
dropped: function (event) {
//To catch the event after dragged
//Value of model which is moving
event.source.nodeScope.$modelValue;
//Source Parent from where we are moving model
event.source.nodeScope.$parentNodeScope.$modelValue;
//Destination Parent to where we are moving model
//Edit: Use "nodesScope" instead of "nodeScope" for dest object
event.dest.nodesScope.$nodeScope.$modelValue;
}};
Hope it works for you too:)
You access the "dropped" item like this.
$scope.elOptions = {
dropped: function(e) {
console.log (e.source.nodeScope.$modelValue);
}
};
Addional information which might be useful can be found on this issue of the project : https://github.com/angular-ui-tree/angular-ui-tree/issues/272
For example in my case, I was dragging from one tree to another one, and in this case, the dropped function must be overriden in the SOURCE tree options (and not the DESTINATION one like I initially thought).
The discussion in the related issue helped me a lot to find this out.
Related
I have mapbox marker objects that are being stored in a Firebase array. They are being loaded as geojson markers on my map and I am also listing those objects in a container with a simple ng-repeat. My goal is to have a function where, if the particular marker is out of view, to remove that marker from the DOM. If the marker comes back into view, to include that back into the ng-repeated list.
Let's say my list is being displayed like this:
<div id="list-item-container">
<div class="list-item" title="{{marker.name}}" ng-repeat="marker in markers">{{marker.name}}</div>
</div>
In my controller, I'm trying to hide and show these list items based on them being in the map bounds like so:
var markers = L.mapbox.featureLayer()
.addTo(map);
markers.setGeoJSON($scope.driverMarkers);
var listingsFromMarker = function() {
var bounds = map.getBounds();
markers.eachLayer(function(marker) {
var inBounds = [], id = marker.toGeoJSON().$id;
var idElement = $('.list-item[title="'+marker.toGeoJSON().$id+'"]');
if (bounds.contains(marker.getLatLng())) {
HOW DO I GET THIS ITEM BACK IN MY LIST???
} else {
idElement.remove();
}
});
};
map.on('move', function() {
listingsFromMarker();
});
Can anyone steer me in the right direction on how to place this ng-repeated item back into the DOM?
Thank you.
This is not the Angular way to do things. Deleting the DOM element that was created by ng-repeat binding ruins the concept... why would you use Angular at all in this case.. In all cases DOM should be manipulated with the help of Angular directives which are controlled via model.
Thus you should store two arrays. One is the real data - all markers. Another contains only markers that are desired to be shown at this moment in the list.
It will look something like below
In view
<div class="list-item"
ng-repeat="marker in markersInView"
title="{{marker.name}}">{{marker.name}}</div>
In controller
var listingsFromMarker = function() {
var bounds = map.getBounds();
var inBounds = [];
markers.eachLayer(function(marker) {
if (bounds.contains(marker.getLatLng())) {
inBounds.push(marker);
}
});
$scope.markersInView = inBounds;
$scope.$apply();//as this happens on mapbox event it isn't in $digest cycle
//so need to tell Angular to update bindings
};
And of cause you need to initialize $scope.markersInView somewhere in the beginning. This code is not presented in OP so I don't invent it. I guess you will figure out how to filter markers on first show
I'm using a kendo grid and have a checkbox column with the following template:
"<input class='gridCheckbox' id='gridCheckbox_#=name#' name='Selected' type='checkbox' ng-model='dataItem.checked'/>"
In addition I'm also using an observableArray as the grid's dataSource.
When clicking the chekcbox the data in the observableArray is changed as expected but no "change" event is triggered.
Here is how I define the observableArray:
var obsArray = new kendo.data.ObservableArray(scope.gridData);
this.gridDataSource = new kendo.data.DataSource({
data: obsArray
});
obsArray.bind("change", function (e) {
console.log(e.action, e.field);
});
"scope.gridData" is the original dataModel. When I click the checkbox the observableArray is changed but not the "scope.gridData". In order to change the "scope.gridData" I want to listen to the "change" event and change the "scope.gridData" manually but as I said the "change" event is not triggered.
Any suggestions to what am I doing wrong and maybe there is a better solution.
Read This
your issue is that kendo uses a copy of your scope object
I manually added an event to my input checkbox (in our class we're using Angular so it was on ng-click="doSomething()" but maybe yours is just click="doSomething" and recorded handling the boolean change manually.
We have the Kendo Observables, too - but I got **lucky because we're also using the Breeze JS stuff where we can do data detection and refresh the grid once the data propagates backwards to the right place to be set to dirty. ( grid.dataSource.read(); )
If you want the full row value, make the click="doSomething(this)" and then capture it as the Sender. Just debug in and you should the dataItem attached to the Sender.
This might help you & this is not the correct figure but i did one example like this similar to your problem
var contentData = [
{ organization: 'Nihilent', os: 'Window' }
];
var nihl = contentData[0];
var viewModel = kendo.observable({
gridSource: new kendo.contentData.DataSource({
contentData: contentData
})
});
kendo.bind($(document.body), viewModel);
contentData.push({ organization: 'Dhuaan', os: 'Android' });
nihl.set('os', 'iOS');
I have a typical structure of a collection holding models.
In the view, each object has an 'edit' button, that should desactivate all 'edit' buttons of other objects.
I wonder what is the best practice of doing that. Thanks!!
You could add a property editable on your models that is default set to true. Then when you click the 'edit' button on one of the views, you could loop through all the models of the other views and set editable to false. On the view you would listen to model changes, and re-render the view. If editable is false you would disable the edit button.
Ok, so I came up with the following approach:
Assume that model has a property status, and when it is modified to active I want to hide the edit button in other entries (or simply disable it).
My collection view listens to a change in a model:
initialize: function(){
this.listenTo(this.collection, "change:status", this.triggerEditable);
},
The listener callback looks like that:
triggerEditable: function(obj){
var triggerValue = null;
// I am interested in a status which became 'active' or stopped being 'active'
if (obj.get("status") == 'active' && obj.previous("status") != 'active') {
triggerValue = "editable:false";
} else if (obj.get("status") != 'active' && obj.previous("status") == 'active') {
triggerValue = "editable:true";
}
// for any other status change - return
if (!triggerValue) return;
// trigger is fired for all other objects in the collection
_.each(obj.collection.without(obj),function(otherObj) {
otherObj.trigger(triggerValue);
});
}
So, when one object becomes active or stop being active, edidable:false or edidable:true are triggered for all other entries. All I need to do is to add to the model view initializer a listener:
this.listenTo(this.model, "editable:false", this.disableEdit);
this.listenTo(this.model, "editable:true", this.enableEdit);
Here I guess I could combine these two lines into one, first by listening to the editable namespace (how??) and then by passing an argument to the function (again, how exactly?).
From here it is straight forward - implement the listener callback:
disableEdit: function() {
var e = this.$el.find('button.edit')
e.attr('disabled','disabled');
}
If somebody has something to add or to make this solution nicer, I will be glad to hear.
Anyway, hope it will be helpful to others!!
I have my view set up with some events and I want to reference, for example, the button element that was clicked because it has a data attribute I need. I want to do it like so:
events: {
'click #testGadget': 'fireEvent',
...
},
fireEvent: function(){
var x = $(this).data('iCanHaz')
}
But the 'this' variable is scoped to the view itself. I know there's a way to accomplish what I'm looking to do but I can't seem to word my question in a way that returns any google hits.
Can simply be done with the event.target property:
fireEvent: function(e){
var x = $(e.target).data('iCanHaz')
}
see Event Object doc
I need help with a script to add an "active" class to a div when a hidden checkbox is checked. This all happening within a somewhat complex form that can be saved and later edited. Here's the process:
I have a series of hidden checkboxes that are checked when a visible DIV is clicked. Thanks to a few people, especially Dimitar Christoff from previous posts here, I have a few simple scripts that handle everything:
A person clicks on a div:
<div class="thumb left prodata" data-id="7"> yadda yadda </div>
An active class is added to the div:
$$('.thumb').addEvent('click', function(){
this.toggleClass('tactive');
});
The corresponding checkbox is checked:
document.getElements("a.add_app").addEvents({
click: function(e) {
if (e.target.get("tag") != 'input') {
var checkbox = document.id("field_select_p" + this.get("data-id"));
checkbox.set("checked", !checkbox.get("checked"));
}
}
});
Now, I need a fourth ( and final ) function to complete the project (using mootools or just plain javascript, no jQuery). When the form is loaded after being saved, I need a way to add the active class back to the corresponding div. Basically reverse the process. I AM trying to figure it out myself, and would love to post an idea but anything I've tried is, well, bad. I thought I'd at least get this question posted while I work on it. Thanks in advance!
window.addEvents({
load: function(){
if (checkbox.checked){
document.getElements('.thumb').fireEvent('click');
}
}
});
Example: http://jsfiddle.net/vCH9n/
Okay, in case anyone is interested, here is the final solution. What this does is: Create a click event for a DIV class to toggle an active class onclick, and also correlates each DIV to a checkbox using a data-id="X" that = the checkbox ID. Finally, if the form is reloaded ( in this case the form can be saved and edited later ) the final piece of javascript then sees what checkboxes are checked on page load and triggers the active class for the DIV.
To see it all in action, check it out here: https://www.worklabs.ca/2/add-new/add-new?itemetype=website ( script is currently working on the third tab, CHOOSE STYLE ). You won't be able to save/edit it unless you're a member however, but it works:) You can unhide the checkboxes using firebug and toggle the checkboxes yourself to see.
window.addEvent('domready', function() {
// apply the psuedo event to some elements
$$('.thumb').addEvent('click', function() {
this.toggleClass('tactive');
});
$$('.cbox').addEvent('click', function() {
var checkboxes= $$('.cbox');
for(i=1; i<=checkboxes.length; i++){
if(checkboxes[i-1].checked){
if($('c_'+checkboxes[i-1].id))
$('c_'+checkboxes[i-1].id).set("class", "thumb tactive");
}
else{
if($('c_'+checkboxes[i-1].id))
$('c_'+checkboxes[i-1].id).set("class", "thumb");
}
}
});
// Add the active class to the corresponding div when a checkbox is checked onLoad... basic idea:
var checkboxes= $$('.cbox');
for(i=1; i<=checkboxes.length; i++){
if(checkboxes[i-1].checked){
$('c_field_tmp_'+i).set("class", "thumb tactive");
}
}
document.getElements("div.thumb").addEvents({
click: function(e) {
if (e.target.get("tag") != 'input') {
var checkbox = document.id("field_tmp_" + this.get("data-id"));
checkbox.set("checked", !checkbox.get("checked"));
}
}
});
});