Why selected object is not display in console when it is clicked - angularjs

I am using this demo: https://github.com/ezraroi/ngJsTree
API reference: https://www.jstree.com/api/#/
I made two examples
First I have a checkbox. When I select any checkbox, it show the selected item object (codepen: http://codepen.io/naveennsit/pen/MKJdOZ?editors=101)
$scope.getSelectedCategories = function() {
alert('---')
var selected_nodes = $scope.treeInstance.jstree(true).get_checked(true);
console.log(selected_nodes);
};
But when I remove this checkbox the click and selected item is not displayed in the console (codepen: http://codepen.io/naveennsit/pen/RrKmxp)
I used same function in both examples, but the second one does not work.

According to the documentation of jsTree .get_checked(true) returns "an array of all checked nodes". If you don't have a check box associated to a node then I'm not sure it will work. Or it will not work without a significant workaround. However, the documentation says that "if tie_selection is on in the settings this function will return the same as get_selected". This may give you the solution you seek. Otherwise you could change .get_checked to .get_selected
The documentation I used can be found here.
It's pretty far down the page to find .get_checked fyi.
EDIT
I decided to just try it myself.
$scope.getSelectedCategories = function() {
var selected_nodes = $scope.treeInstance.jstree(true).get_selected(true);
alert(JSON.stringify(selected_nodes));
};
This alerted the object.

Related

Why is AngularJS form not updating validity until clicking into another field and changing value?

Good morning! I am still fairly new to AngularJS and did not find an answer that I could fully comprehend.
There is a form structured like this:
Name
Email
Color [Option Red, Option Blue]
REQUIRED Field that only appears if Option Blue is chosen for 'Color'
When selecting Option Blue, the second set of fields appear. However, when unselecting 'Option Blue', the required fields are again hidden, but the form still 'sees' that the field is empty until I click into another field (like 'Name') and type another value.
A condition checks the boolean $form.$valid every time the event listeners (?) fire off, which is onItemSelect and onItemDeselect and onSelectionChange.
From what I understand of Angular, I... think that another digest(?) cycle has not started (?) until I click and type into another field? Sorry for all of the question marks - my knowledge is a little flakey and I can't quite paste the source code for reasons.
Is my understanding correct? And if so, are there any recommended ways to resolve this issue?
Edit: I have added some example code below with dummy variable and object names, plus some pseudo code to summarize larger sections of code.
<script>
var app = angular.module('myApp',[some stuff]);
app.controller('myContropper', function ($scope, $rootScope, $timeout) {
[some variables for scope]
$scope.color = {};
$scope.optionB = {
hue: null;
saturation: null;
};
[some other variables that only have values of OptionB is chosen and subsequent fields are populated]
$scope.colorChange = function() {
if color is changed, clear all associated arrays and values by setting it to either '[];' or 'null;'
};
$scope.checkForm = function() {
if OptionB is not chosen, clear all options related to OptionB
use $scope.form.$valid boolean value and do something with it
};
function onItemSelect(item) {
if OptionB is selected, set the flag for that option to true
$scope.checkForm();
}
function onItemDeselect(item) {
if OptionB is not selected, set the flag for that option to false
$scope.checkForm();
}
}
</script>
I had set up some debugging alerts. I notice that when I unselect OptionBlue, the alert will have the following line:
requiredFieldifOptionBisChosen: object Object
However, upon clicking on another field and typing any value, the form will refresh (?) the validity, and it'll say:
requiredFieldifOptionBisChosen: null

AngularJS - HTML binding not working properly

In my angular app, there are two pages (list & checkout). In the list page the user could search for an item and the searched item will be displayed and then the user can select the item and continue to checkout.
From the checkout page the user could return back to list page, and at that time all the items in the list page should be same as how it was left before.
For implementing this feature, my code is
on moving from list page to checkout page, all the scope data are stored in a service
returnsService.setScopeData($scope);
And on returning back from checkout page to list page, this saved data are retrieved from service and assigned to scope variables.
var restoreScopeData = returnsService.getScopeData();
if (restoreScopeData) {
for (var key in restoreScopeData) {
if (key.charAt(0) != '$') {
$scope[key] = restoreScopeData[key];
}
}
}
This works fine to an extend, and I can see the list page same as how I left it.
But the problem is, now I'm not able to search for new item in the list page.
When ever a search happens, the items are populated to $scope.listSearch and they are displayed in html {{listSearch}}.
In the error case also,
I can see the new search data getting assigned to the $scope.listSearch, but the HTML binding is not happening.
I tried calling $scope.$apply() after the search assigning, but still not working.
Storing complete scope isn't good idea. You can just store the vars you need. Also, you can use localStorage for this.
As I understood, making new call is not an option, so you can try use $timeout.
$timeout(function() {
$scope.listSearch = myValue;
});
Instead of doing this, you may for localStorage or sessionStorage as suggsted by John.
You may check below link for example
https://www.codeproject.com/Articles/1015515/Working-With-Client-Side-Local-Storage

What is the right way to select by value in a dropdown?

I'm having a bit of an issue with Angular and selecting an item from a dropdown and making Angular update the model.
I've been searching through StackOverflow, but only with partial luck.
The problem is that when i'm manually setting a value on a model, my dropdown updates correct, but the model itself does not update;
$scope.setSelected = function(){
$scope.selected.id = 15;
//$scope.$apply();// $apply already in progress
}
From various answers on StackOverflow, I've found out that Angular does not know about this update and the suggested answer is to run either a $scope.$apply() or a $scope.$digest(), but both throw a $apply already in progress exception. I have a feeling that this is not the correct way for me to do it, since it doesn't make sense, that you have to trigger an event to select by value.
What is the correct way to select an item in a dropdown by a given value?
Full code example can be found at https://jsfiddle.net/c2x3jvut/
When clicking the "Select dinnerman" button, the dropdown updates correct, but the shown model and when clicking "Log selected" it only shows the selected model, but with an updated id.
You can use $filter to get whole object instead of each property.
$scope.setSelected = function(){
$scope.selected = $filter('filter')($scope.persons,15,'id')[0];
//$scope.selected.id = 15;
//$scope.$apply();// $apply already in progress
}
Here is the modified version
ng's select binds its value based on its ngModel, which is being manipulated incorrectly in the example. The correct method is to change the reference of the ngModel rather than the select's id:
$scope.setSelected = function () {
$scope.selected = $scope.persons[1]; // yes
// $scope.selected.id = 15; // no
};
Fiddle might have been updated to show the effects.
Not sure I understand your question, but still...
You may include in each entry of the dropdown:
...ng-click="setSelected(<value>)"...
and, of course, add a parameter to the function.
By the way, are you aware that in the fiddle example you are selecting ID 15 in function setSelected?
You are just updating the current model with an ID. But when you see carefully the name and age remains same. Further you need to update the whole object as below:
$scope.setSelected = function(){
$scope.selected.id = 15;
$scope.selected.name = "Dinner-man";
$scope.selected.age = 20;
}
Or anyother way to directly updates the object.

AngularJS typeahead select on blur

I'm using typeahead through in my AngularJS project and I would like to have it select the entry if I type the full value and click out of the field.
I've put together an example of what I mean
http://plnkr.co/edit/NI4DZSXofZWdQvz0Y0z0?p=preview
<input class='typeahead' type="text" sf-typeahead options="exampleOptions" datasets="numbersDataset" ng-model="selectedNumber">
If I type in 'two' and click on 'two' from the drop down then I get the full object {id: 2, name: 'two'}. This is good, if however I type 'two' and click to the next field without selecting is there a way to accept the top of the list on loss of focus on a text field?
I'm not sure if I'd want to have that sort of functionality in my app. The user hasn't actually selected anything. So selecting something for them would introduce frustrations.
But I do understand that often odd requirements are needed. In this case, I'd attack it using ngBlur. Assign a function to be called on blur. You can grab the contents of ng-model and then loop through your data (assuming static & not being sent via server) to find a match.
You can most likely just look at the source code of your typeahead directive and strip out the part does the comparison and then choose the first item in the array.
Unfortunately the underlying component does not emit any events for this condition. This will make the solution more complex. However when the value is being entered and the Typehead magic has happened you can supplement those events and catch them to update your ngModel.
I have created a plnkr based on your plnkr and although have not cleaned up but it is a working plnkr doing by far what you need.
The gist of this is following code however you can put this code wherever best suited
The explanation below:
//Crux - this gets you the Typeahead object
var typeahead = element.data('ttTypeahead');
//This gets you the first
var datum = typeahead.dropdown.getDatumForTopSuggestion();
if (datum){
//you can do lot of things here however
//..I tried to - fill in the functionality best suited to be provided by Typeahead
//for your use case. In future if Typeahead gets this
//..feature you could remove this code
typeahead.eventBus.trigger("hasselections", datum.raw, datum.datasetName);
}
In the above code you can also save the datum somewhere in the scope for doing whatever you like with it later. This is essentially your object {num: 'Six'} Then you may also use ngBlur to set it somewhere (however the plnkr I created doe snot need these gimmicks.)
Then further down - ngModel's value is set as below
element.bind('typeahead:hasselections', function(object, suggestion, dataset) {
$timeout(function(){
ngModel.$setViewValue(suggestion);
}, 1);
//scope.$emit('typeahead:hasselections', suggestion, dataset);
});
I'm with EnigmaRM in that ngBlur seems to be the way to do what you want. However, I agree with the others that this could be somewhat strange for the end users. My implementation is below (and in plnkr). Note that I trigger on ngBlur, but only apply the model if and only if there is only one match from Bloodhound and the match is exact. I think this is probably the best of both worlds, and hope it should give you enough to go on.
$scope.validateValue = function() {
typedValue = $scope.selectedNumber;
if(typedValue.num !== undefined && typedValue.num !== null)
{
return;
}
numbers.get(typedValue, function(suggestions) {
if(suggestions.length == 1 && suggestions[0].num === typedValue) {
$scope.selectedNumber = suggestions[0];
}
});
};

knockout checkbox binding selected value

I am learning knockout and was trying to build a page that will build a list of selectable users.
JSFiddle: http://jsfiddle.net/Just/XtzJk/3/ (I am unable to get the data assignment right).
The data assignment is working in my page as I make a call to Controller, like below and it binds to the controls as expected
$.getJSON("/Wizard/GetUsers",function(allData){
var mappedUsers = $.map(allData.AllUsers, function(item){return new User(item)});
self.AllUsers(mappedUsers);
if(allData.SelectedUsers != null){
var mappedSelectedUsers = $.map(allData.SelectedUsers, function(item){return new User(item)});
self.SelectedUsers(mappedSelectedUsers);}
});
Problems:
a.) What's wrong with the JSFiddle I wrote? Got it working.
b.) In my code I am able to get the function for selected checkbox invoked but I am unable to get the value stored in the "User" parameter that I receive in the function. In Chrome JS console I can see the user object has the right value stored, I just am unable to retrieve it. Got this by doing ko.toJS().
Thanks.
EDIT:
Ok, I got my JSFiddle working, I had to select Knockout.js in the framework. The updated fiddle: http://jsfiddle.net/Just/XtzJk/5/
Also, for getting the selected checkboxe's value I did
ko.toJS(user).userName
But I think I'll take the approach of selecting values from a list and then on click move them to another "Selected" list and remove the values from the previous ones. Got this idea from this post: KnockoutJS: How to add one observableArray to another?
OK, I think I've got the solution you need...
I started by setting up an observable array of selectedUserNames, and I applied this to the <li> elements like this:
<input type="checkbox"
name="checkedUser"
data-bind="value: userName, checked:$root.selectedUserNames" />
[Note: it's important to declare the value before declaring the checked binding, which threw me for a bit… ya learn something new every day!]
Why bind an array of userName values to the checked binding? Well, when an array is passed to the checked binding, KO will compare the value of each checkbox to the values in the checked array and check any checkbox where its value is in that array. (Probably explained better in the KO documentation)
Then, while I left the observableArray for SelectedUsers, I set up a manual subscription to populate it, like so:
self.selectedUserNames.subscribe(function(newValue) {
var newSelectedUserNames = newValue;
var newSelectedUsers = [];
ko.utils.arrayForEach(newSelectedUserNames, function(userName) {
var selectedUser = ko.utils.arrayFirst(self.AllUsers(), function(user) {
return (user.userName() === userName);
});
newSelectedUsers.push(selectedUser);
});
self.SelectedUsers(newSelectedUsers);
});
[I had originally tried to set up a dependent observable (ko.computed) for selectedUserNames with functions for both read and write, but the checkbox wasn't having it.]
This subscription function examines the new selectedUserNames array, looks up the user from AllUsers whose userName matches a value in that selectedUserNames array, and pushes matching User objects to the SelectedUsers array… well, actually it pushes each matching User to a temp array and then that temp array is assigned to SelectedUsers, but the goal is met. The SelectedUsers array will now always contain what we want it to contain.
Oh, I almost forgot… here's the fiddle I created, so you've got the full solution: http://jsfiddle.net/jimmym715/G2hxP/
Hope this helps, but let me know if you have any questions

Resources