I would like to know how to access jsTree node attributes after the node's checkbox was clicked.
I use $("#jstree").bind('check_node.jstree', function(e, data) { to trigger my code after the checkbox was clicked.
Now I want to access node's attributes. But I don't know how to use data object so I can get the attributes. So let's say in my jsfiddle I want to display the value of the attribute along with the text "clicked and checked"
Could you please explain how & why? I am lost how to reference jsTree/jQuery objects.
jsfiddle working sample
==== Update
In jsTree data definition node attributes could be defined. I want to programatically check the attributes and then fire different code base on the attributes. In my case "log" attribute.
data = [
{
"data": "Basics",
"attr":{"log":"shared"},
},
{
"data": "All",
"attr":{"log":"bdrs"},
}
]
you could just do:
$("#jstree").bind('check_node.jstree', function(e, data) {
$("#list").append('<BR>clicked and ' + node_is_check(data));
var node = data.rslt.obj;
console.log( node.attr("log") ); //shows bdrs when All is checked
});
Updated fiddle: jsFiddle Demo
Did you mean something like this
Related
I am using jstree and would like to make some ajax calls when a node is selected. I do not want to trigger the ajax call if the same node is clicked again. The jstree example for listening events uses changed.jstree
as below:
$('#jstree')
// listen for event
.on('changed.jstree', function (e, data) {
//my custom code here that should trigger if a new node is selected
});
However this gets triggered if I click the same node twice. I couldn't find anything in the data or event object e that would tell me whether this is same as the previously selected node. Is there anything in jstree to help me figure this out? If not what is the best way to figure this out?
I found that we can use changed plugin to determine the selected and deselected nodes.It's the first plugin shown here
Create jstree and include changed in the plugins array:
$('#jstree').jstree(
{
"core": {
"multiple": false,
// so that create works
"check_callback": true,
"data": menu
},
"plugins": ["changed"]
}
);
If both selected and deselected arrays are empty that means the selection hasn't changed:
$('#jstree').on('changed.jstree', function (e, data) {
if (!(data.changed.selected.length === 0 && data.changed.deselected.length === 0))
{
//This is when something is really changed.
});
I want to perform operation after successfully loaded the partial page using $http service in angular.
The operation is to check the checkbox based on the scope value.
Please anyone help me.
Source Code here:
This is actual code.
$http({
url : './resources/staticPages/custom-object-filter.html',
method : "GET"
}).success(function(data, status) {
$scope.data = data;
jQuery("objectViewPartial").html($compile($scope.data)($scope));
//console.log($scope.selected);
if(angular.equals($scope.selected, "ShowActivatedObjects")) {
$("#ShowActivatedObjects").attr('checked','true');
} else {
$("#ShowActivatedObjects").attr('checked','false');
}
}).error(function(data, status) {
console.log("some error occured partial page");
});
After getting success the below code is not working.
if(angular.equals($scope.selected, "ShowActivatedObjects")) {
$("#ShowActivatedObjects").attr('checked','true');
} else {
$("#ShowActivatedObjects").attr('checked','false');
}
I placed this code inside of success function.
Please advice where i need to place this code.
A short Angularjs excursus:
In general you should minimize the use of jQuery within angularjs as far as you can, because both concepts are working against each other.
Angularjs is based on bindings between scope variables and the template expressions. So for a check box you can easy handle it without jQuery as follows:
A good explanation you can find here:
https://stackoverflow.com/a/14520103/4852206
What you are seeing here is, that you i.ex. can bind the checkbox inputs to an array. If you are changing the array content, the checkboxes are listening and do change there state (checked or unchecked) just on the fly without the need of checking if it is active and without the Jquery dom manipulation needs.
I wrote the above excursus, because you will run into huge unstructured and unreadable code if you will use your way as best practice. Also I am afraid, that you are using your code within your controller function. In Angularjs the controller is NOT for dom manipulation, you should only use it for setting / changing the scope variables or just a minimal business logic (in general avoid it here!) Business logic should go into services and dom manipulation should go into directive's.
Your question:
Please provide more information for your problem / logic. Please provide sample checkboxes, and sample information that you pull from the server via $http
Please provide also what you want to achieve exactly. Then we can help you with a clear answer.
Sorry I know this is no answer, but I cannot add comments actually cause I am quite new here.
EDIT
Ok thanks to your comment to #Likeee I think I got you. You have a set of checkboxes on your page. On page load you want to check which checkbox needs to be active. The logic which checkbox is active on pageload comes from the server side, is that correct? If yes I would handle it as follows with angular structure (I created a fiddle for a better understanding: https://jsfiddle.net/pfk9u3h0/4/)
First you need your HTML:
<body ng-app="myApp" ng-controller="AppController">
<label ng-repeat="filter in productFilter">
<!--
simply checking if the array contains the entry. if not, it is not selected. On a click event, the selected item is added to the array.
-->
<input
type="checkbox"
value="{{filter}}"
ng-checked="selection.indexOf(filter) > -1"
ng-click="toggleSelection(filter)"/> {{filter}}
</label>
"selection Array within SelectionService": <br />{{selection}} <br /><br />
as you see, the array is also updating when you check or uncheck a box
</body>
This HTML snipped does several things:
First it declares which controller (here "AppController" to use.
Second it creates a label with a checkbox inside. The label has the Angularjs directive ngRepeat and causes to show as much checkboxes as the array "productFilter" within AppController contains.
The Javascript contains a controller which is talking to your HTML and to a service. The service is also declared below.
Controller:
app.controller("AppController", function( $scope, SelectionService ) {
// available filter checkboxes
$scope.productFilter = ['Red pants', 'Green Pants', 'Yellow pants', 'Blue pants'];
// selected filter
// normally you just would have this: $scope.selection = ['Red pants', 'Blue pants'];
// But now you want to pull the selection elsewhere:
// The selection should go in a service, because it can happen, that other pageviews of your page shall
// change the values or even get the selection as well.
$scope.selection = SelectionService.selection; // Bind the selection to the service
// With the proper binding, you can change the selection within other modules / pages etc. and this
// checkbox fields will update based on the service data!
//I just initialize the service selection array, butbut you really want to pull it from server like this:
// SelectionService.loadSelection()
// .then(function(data) {
// if you like, yo can do sth. with this promise callback
// });
// Change selection for the clicked input field
$scope.toggleSelection = function toggleSelection(filter) {
var idx = $scope.selection.indexOf(filter);
// is currently selected
if (idx > -1) {
SelectionService.removeSelection(idx);
}
// is newly selected
else {
SelectionService.addSelection(filter);
}
};
});
With $scope.productFilter = ['Red pants', 'Green Pants', 'Yellow pants', 'Blue pants']; we declare an array over which we iterate within our HTML. This contains all checkboxes with names.
Now we need an array with all selected checkboxes. This is saved in $scope.selection and is bound to the service which i show at the end:
$scope.selection = SelectionService.selection;
The rest within the controller is just to set the new values, if you uncheck or check a checkbox
The Service:
app.service("SelectionService", function ($http, $q) {
var obj = {
selection : ['Red pants', 'Blue pants'],
loadSelection : function(){
var that = this;
var deferred = $q.defer();
var config = {
responseType : "json",
cache: true
}
$http.get("/getSelectionFromServer", null, config)
.success(function(response){
if(response) {
// IMPORTANT: Use a deep copy, otherwise you will loose the binding
angular.copy(response,that.selection);
}
deferred.resolve(response);
})
.error(function(){
deferred.reject();
});
return deferred.promise;
},
addSelection : function (filter) {
this.selection.push(filter)
},
removeSelection : function (index) {
this.selection.splice(index, 1);
};
return obj;
});
The Service is doing 4 things: It holds and initilizes (if you like) an array "selection". And it offers a method to load new data from server and save it to the array. Here it is important that you use the copy method, otherwise you will loose any binding. And it offers methods to set and remove selections.
in my example i dont use the load method, because I do not have any serverside scripts here...I just take the initialization values. But you should use my load method.
Hi your comparison is probably bad.
if(angular.equals($scope.selected, "ShowActivatedObjects")) {
I don't know what value is in $scope.selected, but i think this value is a checkbox state which is boolean type. So you are comparing boolean with string.
Check out https://docs.angularjs.org/api/ng/function/angular.equals
Finally i achieved my requirement:
// $scope.getCustomObjectsBasedOnObjectTypeSelection = getCustomObjectsBasedOnObjectTypeSelection;
$scope.selected = ['Show All'];
var IsActive = "";
$scope.objectSelection = function objectSelection(objectType) {
var idx = $scope.selected.indexOf(objectType);
// is currently selected
if (idx > -1) {
$scope.selected.splice(idx, 1);
}
// is newly selected
else {
$scope.selected.push(objectType);
}
};
On text cells that have editable: true I have no issue's writing to the store - the cell writes to the store by itself automatically, but none of my cellWidgets write to the store.
here is a snippet of my code (the top lines 2-5 that are commented out is something else I tried without luck):
{ id: 'identColumnId', field: 'identColumn', name: 'Ident', width: '77px',
// editable: true,
// editor: 'dijit/form/ComboButton',
// editorArgs:{
// props:'store: identMemStore'
// },
widgetsInCell: true,
navigable: true,
setCellValue: function(one,two,cellWidget){
var rowIndex = cellWidget.cell.row.id;
var toggle = identMemStore.get(rowIndex).identColumn;
if (toggle)
{
this.identColumn.set('label', "Override");
this.identColumn.set("checked",false);
}else
{
this.identColumn.set('label', "Use Input");
this.identColumn.set("checked",true);
}
},
getCellWidgetConnects: function(cellWidget, cell){
// return an array of connection arguments
return [
[cellWidget.identColumn, 'onClick', function(e){
var rowIndex = cellWidget.cell.row.id;
var curValue = identMemStore.get(rowIndex).identColumn;
if (curValue === true){
cellWidget.identColumn.set('label', "Use Input");
cellWidget.identColumn.set("checked",true);
// Write to store manually...
// identMemStore.data[rowIndex-1].identColumn = false;
} else if (curValue === false){
cellWidget.identColumn.set('label', "Override");
cellWidget.identColumn.set("checked",false);
// Write to store manually...
// identMemStore.data[rowIndex-1].identColumn = true;
} else {
console.log("ERROR");
}
}]
];
},
decorator: function(){
return "<button data-dojo-type='dijit/form/ToggleButton' data-dojo-attach-point='identColumn' ></button>";
}
},
Also I have setup the code to catch the changes on a cell edit after data has been written to the store. Again, my text cells work just fine and the following code is executed, but my other dojo widgets don't write to the store and therefore don't set off the following code which is executed after an edit is completed and the store has been written to.
identGridx.edit.connect(identGridx.edit, "onApply", function(cell, success) {
var item = cell.row.data();
var id = cell.row.id;
console.log('Row with ID ' + id + ' is modified. New value: ' + item);
});
How do I get my dojo widgets within the cellWidgets to write to the gridx store??
You can have any cellWidget save to the store automatically by having the Edit module setup correct. See this documentation: Dojo Edit Module
When a grid includes the Edit module, this does not mean that all the cells are immediately editable. Instead, we must tell the grid which columns contain editable fields. We do this by setting the column property called editable to true. The default is false which means that cells in that column are not editable.
When a cell is to be edited, a new instance of Dojo widget (Dijit) is created at the location of the cell on the screen. This widget is responsible for showing the current value and allowing the user to change that value. By default, the widget used is an instance of dijit.form.TextBox however different widget types can be used. The property called editor should be set to the String name of the Dijit class to be used. Remember to define an AMD include of this class type if it is used. Another column property called editorArgs can be used to supply properties to the widget named in editor. The editorArgs property is an object which the following properties:
props (String) - Set of properties defined on the Dijit Widget
fromEditor (function(storeData, gridData))
toEditor (function(storeData, gridData, cell, editor)) - Function is called to populate the editor widget. The editor parameter is a reference to the Dijit widget used to edit the cell.
constraints (Object) - Additional properties passed to the editor.
useGridData (Boolean) - Should the editor be fed with data from the Store or from the Grid? The default is false which means to use the store data. This property is not used if toEditor is supplied.
valueField (String) - The property of the editor that holds the value. This is normally value which is the default.
When the edit of the cell has finished, the data entered is written back into the store. We can change how this is achieved by providing a function to be called to apply the change using our own logic. The property for this is customApplyEdit which is a function with the signature function(cell, value). It is the responsibility of the code to set the value of the cell to be the value passed in as a parameter.
See this jsfiddle: Working example
I am using Select2 as multiselect on an input field. I am trying to find out which choice is being clicked, but if I look at the event thrown when clicking a choice ("choice-selected") all I can find is event.target.value which is the data array with all selected options (choices). Basically I want to access the clicked value so I can let the user edit a custom attribute in that specific choice. How could I go about doing that?
JSFiddle of the problem: http://jsfiddle.net/JtTTF/
$(test).bind("choice-selected", function(e) {
alert(e.target.value);
// this is where i would like to access the clicked choice id so i can edit the custom data attribute "reason"
});
I ran into this as well. After examining the select2.js source code, I found that the choice-selected event passes a second parameter: the dom element you clicked.
This dom element contains a data object with key "select2-data".
Your code might look something like this:
$(test).on("choice-selected", function(e, choice) {
var data = $(choice).data('select2-data');
alert(data.reason ? 'Reason: ' + data.reason : 'No Reason');
});
I've updated your jsfiddle accordingly.
Try
var selected = {};
$(test).change(function () {
var selections = $(this).select2('data');
$.each(selections, function (idx, obj) {
if (!selected[obj.id]) {
selected[obj.id] = obj;
$('#selectedText').text(JSON.stringify(obj));
return false;
}
})
});
Demo: Fiddle
Note: Haven't seen whether there is inbuilt support to do this, but a custom implementation
The following code performs an autocomplete for city and then selects the associated state. It works well if I follow the convention of Id: City and State. I'm running into situations where i have multiple city/state controls on a page with different ids.
Can someone please help me refactor this code to be more generic?
Thanks
$("#City").autocomplete({
source: function (request, response) {
$.ajax({
url: "http://ws.geonames.org/searchJSON?country=US",
dataType: "jsonp",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
name_startsWith: request.term
},
success: function (data) {
response($.map(data.geonames, function (item) {
return {
label: item.name + (item.adminName1 ? ", " + item.adminName1 : ""),
value: item.name,
code: item.adminCode1
}
}));
}
});
},
minLength: 2,
select: function (event, ui) {
$("#State").val(ui.item.code);
}
});
It looks like your problem would be that when one #City is autocompleted, all the #States update to that one selection, eh? This is partly because you've violated an html rule. ID's are supposed to be unique.
So I would recommend the following:
Make your Id's unique, preferably named in a way that matches what they're for (like id="homecity", id="vacationcity" etc.)
Add a class to your cities and states inputs that you're binding to.
Consider making your state inputs readonly if they aren't already. That lets users know that they aren't supposed to type there and prevents UI events and interactions. Hopefully it doesn't disrupt the autocomplete plugin.
Add an attribute to the markup for the cities to indicate which state input they'll be modifying.
Tying it all together, because I can't put code samples in the middle of the list apparently...
Html:
<input id="homecity" class="autocomplete-city" stateid="homestate"></input>
<input id="homestate" class="autocomplete-state" readonly="readonly"></input>
Javascript:
$(".autocomplete-city").autocomplete({
source: function (request, response) {
$.ajax({
// your normal ajax stuff
});
},
minLength: 2,
select: function (event, ui) {
// Updated. 'this' is captured in the closure for the function here
// and it is set to the dom element for the input. So $() turns it
// into a jQuery object from which we can get the stateid attr
$("#"+$(this).attr('stateid')).val(ui.item.code);
}
});
And viola! Each input is generically tied to the state they will control. No more conflicting ids and no more exploding event handlers.
You could also pull this off with jQuery data, if you don't like poluting your markup with non-standard attributes (by which I mean the stateid="homestate" in the html section).
Edit: This next paragraph explanation wrong.
According to the docs, in the select function, the ui.item is the jQuery element for the input that has been autocompleted, so it should be the correct #homecity and the attr call should return the correct value for #homestate (keeping with the example). But I've not tried it, so you might want to throw in some null and/or undefined checking in there.
Edit: the ui.item param passed to the select function is the item selected from the menu, not the jQuery object for the input element. ui has the following structure:
Object {item: Object}
item: Object
code: "AK"
label: "Jeuno, Alaska"
value: "Jeuno"
The correct way to get the attr for the state to update is in from this, captured in the closure of the select function as the DOM element for the input. So running the jQuery function on it $(this) gets you the jQuery object from which you can get your attr() or data().
JSFiddle with multiple autocompletes here: http://jsfiddle.net/KBVxK/1/