TyperError: Cannot read property 'length' of undefined - angularjs

Our team is using angularjs to develop a ServiceNow widget and we are seeing "TyperError: Cannot read property 'length' of undefined" in our console:
When we click on "at eval", it takes us to this particular snippet of code with line 321 highlighted:
We can't seem to figure out what's causing that error. We are using $watch on an array ($scope.data.list) and have read that $watchCollection might be better, but we tried that with no change. Any ideas what could be causing this error and how to get rid of it?

From the code you have posted, you haven't defined or nor declared
$scope.data.list (I'm assuming $scope.data is defined somewhere). To
resolve that, you need to at least declare your $scope.data.list first to watch over it.
Coming to the $watch part, it depends on what your requirement is.
$scope.$watchCollection looks for changes made in the array as well as elements whereas,
$scope.$watch will only look for changes made if the array is totally
assigned to a different one. Otherwise, if you want to watch deep, you can
use $scope.$watch with a boolean true variable passed as a third
argument to it.
Refer this link for the full documentation - https://www.sitepoint.com/mastering-watch-angularjs/

As of my knowledge $watch on $scope.data.list called whenever any value changed in this collection
So by looking at error it seems like $scope.data.list list in no longer exits in $scope.data. Try to find out where $scope.data is going to change.
And use below syntax for watch on collection
$scope.$watchCollection('names', function(newList,oldList) {
if(newList && newList.length) {
$scope.data.list = newList.length;
}
});

Related

Reactive non-mongo variable in angular-meteor

I couldn't find an answer or a solution to a challenge yet: How can I bind a variable (Session variable, no mongo collection) reactively in angular-meteor?
I'm converting from standalone meteor. Here I could use the template.helper method. As I can't use templates (and iron:router) anymore with angular-meteor and angularui-router, I can't bind reactivity to the helper anymore (at least in my understanding).
I tried this in an meteor-angular controller, which belongs to a sentence.tpl file:
$scope.parsestring = function(input_string){
tokenizer(input_string);
};
$scope.sentence_type = Session.getJSON("current_sentence.sentence_type");
Tokenizing works (I can see it in the debugger), but the value is only displayed, when I reload the page. What I want to achieve is tokenizing a string from an input field into a JSON representation (the tokenizer takes care of that) and displaying it similtaniously from the JSON representation in a structured way (separate html input elements, which are created dynamically). sentence_type is the variable that should be used on the html-page to show and change the sentence type, which can change while typing.
Anybody has some hints? Maybe, I could also use some Angular feature that I don't know?
Cheers,
Jan
Code repo:
My current code looks like this:
My code looks similar to this:
angular.module('ngaignt').controller("InteractorCtrl", ['$scope', '$meteor', '$meteorCollection',
function ($scope, $meteor, $meteorCollection) {
// Autorun is necessary to make reactive variables out of the JSON returns
var c = Tracker.autorun(function (comp) {
$scope.verb_type = Session.getJSON("current_verb.type");
$scope.object_type = Session.getJSON("current_object.type");
$scope.verb_attributes = _.toArray(Session.getJSON("current_verb.attributes"));
$scope.object_attributes = _.toArray(Session.getJSON("current_object.attributes"));
if (!comp.firstRun) {
// only do not do aply at first run becaulse then apply is already running.
$scope.$apply();
}
});
$scope.parsestring = function (input_string) {
interactor(input_string);
};
//$scope.on('$destroy', function () {c.stop()});
}]);
To use reactive variables, you need a reactive computation. You may need to use Tracker.autorun:
$scope.parsestring = Tracker.autorun(function(someStringInSession){
tokenizer(Session.get(someStringInSession));
});
Or you can use Tracker.autorun(func) wherever you use a reactive variable to reactively rerun a function when the variable changes.
good question and the best answer depend on your needs.
There are 2 possible solutions:
If you want to bind a Session variable to a scope variable, use the $meteorSession service.
What it does is that every time the scope variable will change, it will change to Session variable (and trigger an autorun if it's placed inside one).
and every time the Session variable will change, the scope variable will change as well (and change the view that it's placed upon).
If you are using the Session variable just to get a variable reactive (meaning trigger an autorun), you should use getReactively . this just returns the already existing scope variable but trigger an autorun every time it changes. a good example of this can be found it our tutorial.
Note: In anyway, when you use Tracker.autorun inside Angular, you need to connect it to a scope. this can be easily done if you replace Tracker.autorun with the $meteorUtils autorun function
Would be great if you could share a repo so that I can look on the broader perspective and could better determine what's the best solution from the two.
Based on another answer about "session" reacitivity, I could solve the problem. Just use the approach described in the link https://stackoverflow.com/a/21046935/4035797. You have to substitute Deps.autorun by Tracker.autorun though as Deps is deprecated and you have to make the scope variables for use in the template reactive (e.g., $scope.sentence_type = Session.getJSON("current_sentence.sentence_type");) and not the tokenizer.

Need explanation on a angular direcive load

I just want to understand why in the following jsFiddle 'here is a lo' is printed three times.
http://jsfiddle.net/wg385a1h/5/
$scope.getLog = function () {
console.log('here is a log');
}
Can someone explain me why ? What should I change to have only one log "here is a log" (that's what I would like this fiddle do). Thanks a lot.
Angular uses digest cycles/iterations to determine when state has changed and needs to update the UI. If it finds any change on one of it's cycles, it keeps rerunning cycles until the data stabilizes itself. If it's done 10 cycles and the data is still changing, you'll see a rather know message: "angularjs 10 iterations reached. aborting".
Therefor, The fact that you are seeing the message displayed 3 times is because you have a simple interface. In fact, you can get up to many more such messages in the log, due to the fact that your directive uses {{getLog()}}. Angular keeps evaluating the expression to see if it changed.
To avoid such problems, under normal circumstances, you should store the value returned by the function you want called only once in the $scope object inside the controller and use that variable (not the function call) in the UI.
So in the controller you'd have $scope.log = getLog() [assuming it returns something, and not just writing to the console] and in the directive use the template {{log}}. This way, you'll get the value only once, per controller instance.
Hope I was clear enough.

ng-table , getData called more than once, why?

For some reason when getData uses angular resource to bring the data it is being called twice, causing the resource to do it REST request twice too <--- bad...
Any idea why and how to solve it?
Here a working testcase/plunker example that recreates this scenario (look at the browser console - "getData being called...." displayed twice ) b.t.w as you can see I'm not really using the resource to bring real data, just to demonstrate the scenario, In my real app I do use the resource to bring real data and its being called twice just like in this example,
Thanks ahead
After looking into the src of the ng-table I noticed the following
$scope.$watch('params.$params', function(params) {
$scope.params.settings().$scope = $scope;
$scope.params.reload();
}, true);
Which means that the tables calls it 'getData' on count/filter/group/groupBy/page/sorting
which explains the behavior I was seeing.
When you call params.count(...) you ask ng-table to refresh data as you change page size. That's why you have two get-data calls.
If you don't want to have paging, then remove calls params.count and params.total.
If you need paging, then set page size and do not change it in getData.
This happened to me with a weird reason. getData get called twice on init (first load) only. changing page or sorting didn't call getData twice. The reason was that at init the ng-table directive was hidden in the template file.
Thank #Alexander Vasilyev. I understood my problem as you said. I want to explain a litte more here. In fact, the object "params" is the object configuration the table ng-table, then if "params" changed (ex: count or a property of the object), ng-table will invoke function getData() to refresh table.
In my case, I want to get information in the object "params" and change it but I dont want to refresh ng-table. I did it by cloning object "params" et work his object copied. Clone the object in JS with jQuery :
var resultParams = jQuery.extend(true, {}, params.$params);
And then, I will work on the object resultParams instead of "params" original.

How to avoid angular.js preemptively fetching data until certain actions

Just started out using angular.js and implemented a directive that reads from a property in the scope that's defined only when a button is clicked. The UI looks fine also because the directive part is only shown when the button is clicked. However in the console when the page is first loaded there is an error message saying "Cannot read property someProperty of undefined".
I must be violating some angular principles but I'm not sure how to fix it. Thanks for the help!
Note: Didn't do a fiddle because this is a general question.
Generally speaking, if you have code patten like
$scope.myObject.property
then you could see the error when myObject is undefined.
One possible way to eliminate the error the code work is make sure the object is always initialized when any property is intended to be referred.
You can put this line before the property is referred.
$scope.myObject = {};
Or do
if($scope.myObject !== undefined){
...
}
There is no rocket science here.

Ext JS - Can I 'chain' methods on a field?

HI,
I am just trying to set a field value and disable it at the same time.
Can this be done in ext js? The docs are very weak on this subject.
something like this generates errors:
myForm.getForm().findField('start_date').setValue('').setDisabled(true);
I'm used to JQuery which does this sort of thing nicely but haven't had luck with Ext.
Thanks for any help.
Actually, Field.setValue does in fact return a reference to the field (docs), so you should be able to call setDisabled (inherited from Component) as you have it. You must have some other issue going on. Maybe findField('start_date') is returning null. You have to make sure all the return values are what you expect. Use Firebug to figure out the error, or break apart your statement and see which call is actually failing.
Anything is "chainable" as long as the return value is the object itself (usually denoted as this in the docs). In jQuery, everything operates on DOM elements, so it is consistent. In Ext, you have lots of components with various behaviors. Sometimes chaining makes sense, sometimes it does not -- just make sure you check the docs when you aren't sure.
i agree with bmoeskau it should work if the field is there and found by the form. I would advise you to to it something like that to prevent errors:
var field = myForm.getForm().findField('xyz');
if(field !== undefined)
{
field.setValue('');
field.setDisabled(true);
}
else
{
// Error Handling
}
This is because setValue() method doesn't return field object. You cannot use setDisabled() in such way.
EDIT: (For those down-voting morons)
From ExtJS documentation:
method: setValue(value)
Parameters:
value : Mixed
The value to set
Returns:
void

Resources