Run a function when variables are loaded - angularjs

I have an NgComponent that is supposed to load data from another file based on a parameter in the tag. Here is an example tag:
<line-graph width="800" height="250" src="table.csv" />
If I attempt to load data based on the src variable in the constructor, it is null. I know that the value is being set, just at a later time. Is there a way to call the load function when the element is full initialized and the variables have been loaded from that DOM?

implement NgAttachAware and run your code in attach().
I read about a bug that even this is not working with some directives recently.
In this case try to run the code inside attach with new Future(() { your code here });
To make code execute every time the value is changed you can make src a setter and the code in the setter gets executed every time the value is changed.
String _src;
#NgTwoWay('src')
String get src => _src;
set src(String val) {
_src = value;
// your additional code goes here
}

You can accomplish this by using the $watch function. The $watch function will be renamed to watch in the next version. Here is an example implementation:
class Component {
#NgAttr("src")
String src;
Scope scope;
Component(this.scope){
scope.$watch(() => src, (value, previousValue){
if (value == null) return;
//load and draw data
})
}
}
In the next version it will look something like this:
class Component {
#NgAttr("src")
String src;
Scope scope;
Component(this.scope){
scope.watch(src, (value, previousValue){
if (value == null) return;
//load and draw data
})
}
}

Related

Get an object's name as the value of this

I am trying to understand the value of this at different points in a script. Questions similar to mine have been answered in this forum but those answers are considerably above my current learning level.
In my code experiments, I am using console.logs to return the this value. The value returned is always as expected, but the format of the returned value is inconsistent, which leads me to wonder why.
This code returns the expected Window object for the first 3 log commands to be executed but returns only the object literal for the 4th command, executed from the object's method.
var myName = {
name: "James",
sayName: function() {
console.log(this, 4);
console.log(this.name)
}
}
console.log(this, 1);
function myFunction() {
console.log(this, 2);
function nestFunction() {
console.log(this, 3);
myName.sayName();
}
nestFunction();
}
myFunction();
I have 3 questions: Why doesn't console.log return the name of the object? Is there a way to make it do so? Is there a simple way to do that other than console.log? Any help would be appreciated.
Ok I was going through your code to see what you specifically mean
here is the short explanation as to why THIS is different in some of the places
This keyword refers to the object it belongs to. Generally you used it to refer to the global window object .That's what is reflecting in your console log 1,2,3 .
Calling this in static javaScript object will return the javaScript object ,not the window object that is what is reflecting in the console.log(this,4).
So it gives you a way to call elements inside a static object .
Another way to understand this keyword is to look at constructors .The best example of the keyword
this
is inside a constructor function
var myObj = function(){
function myObj(ref)
{
this.name = "";
this.Item = "";
this.ref = ref;
this.speak();
}
myObj.prototype.speak =function()
{
this.name = 'James';
this.item = 'cheese';
console.log(this.ref)
//and the constuctor object
console.log(this)
}
return myObj;
}();
var e = new myObj('a Refrence string');
This should give you a basic understanding of how this works
here is more info to get you started Wschools.com

function in rootscope, can't access rootscope variable

In my app.run I have an function which get some text from an global variable from an other file. In that variable there are some keywords with an language attribute, which allows me to only get the requested text and filter out the right language.
I made an function for that but I can't get access the $rootScope.language variable in that function which I need for getting the right text.
function getTourTranslation(key){
console.log("getTourTranslation", key);
var lang = $rootScope.language;
var step = _.get(steps, key);
return step[lang]
}
So language is undefined, and so $rootScope.language is, but the variable exists and contains the right language key for the current language on the site. How can I get the content of that variabele without passing the language as variable into the function?
I also tried as $rootScope.getTourTranslation = function(key) but no luck
edit:
This is how the language variable is filled. We use angular-translate, so that is the $translate service. This code is placed above the getTourTranslation function.
$rootScope.changeLanguage = function (langKey) {
if(langKey){
if(langKey.length == 2) {
$translate.use(langKey.toLowerCase()+"_"+langKey.toUpperCase());
$rootScope.language = langKey;
} else if(langKey.length == 5) {
$translate.use(langKey);
$rootScope.language = langKey.substring(0,2);
}
}
};
$rootScope.$on('$translateChangeSuccess', function () {
if($translate.use()){
$rootScope.language = $translate.use().substring(0,2);
if($state.$current && !$state.$current.self.abstract) {
$state.reload();
}
}
});
$rootScope.changeLanguage($translate.use());
It is not possible that variable defined on $rootScope is not available withing the same context.
I can imagine only one case:
it calls getTourTranslation so early so none of changeLanguage or $translateChangeSuccess handler ran
The problem was, that $rootScope.language was called before it was initialized.
So, I placed the call to the getTourTranslation() function in an function which is called after firing an button. So, the right variables are now only initialized when they are needed instead of always.
So, I fixed two things, and that all based on the comment from #BotanMan

Angular - Objects seem bound to eachother but arent

I have an edit page where the user can edit a file in the system, and then save it. When loading the file, I make two objects out of the result, one is bound to the view and the other I wish to keep (in its original state) until "save" is clicked, and then use it to compare vs the view-bound object, to see if any changes have been made.
So, when the page loads, this is being run
$http.get('/api/files/' + $stateParams.id)
.then(function (result) {
vm.fileTemp = result.data;
vm.fileTempCopy = result.data;
The fileTempCopy is not being touched or referenced by anything in the view or elsewhere in the controller, except in the save-method, where i check if they are alike or not. But somehow, both of them are updated when i make changes to the input fields (as if they were both used as ng-model for the inputs).
if(vm.fileTemp === vm.fileTempCopy)//in save-function
is always true, and their fields are exactly the same.
Why does this happen and how can I solve it?
Using the assignment operator, you are actually just referencing the original array. Arrays are reference types. That means, that they don't actually store values, they only store references to those values. What you where doing is copying a reference to a memory location, meaning that any changes to the memory at that location (including removing elements) will be reflected in both arrays.
So you will want to do this instead:
vm.fileTemp = angular.copy(result.data);
vm.fileTempCopy = angular.copy(result.data);
here is a very basic approach to checking an object's "value equality".
function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
// If values of same property are not equal,
// objects are not equivalent
if (a[propName] !== b[propName]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
//After your update Outputs: false
console.log(isEquivalent(vm.fileTemp, vm.fileTempCopy));

run a function once previous function complete

In the success callback to an ajax query, I have to
a) update the property of an object in an array (and I have to locate that object in the array)
b) save that array again in storage
c) broadcast an event
I'm (trying to) accomplishing that by doing this (code below)
updateTheArray(myarray,'date', $scope.date);
myStorage.put(myarray);
$scope.$broadcast('alldone');
As I'm concerned these are happening out of order or could happen out of order,I would like to be able to do something like (in pseudo code) in the success callback
var updated = updateTheArray(); //update a property on an object in array
updated.promise().then(function(){
myStorage.put(array); //saves
}).done(function(){
$scope.$broadcast('alldone'); //broadcast
}
However, the way I've written the storage and the updateTheArray function are not setup to do that.
Is there a way in Angular to make sure the next function only runs once the first one is complete?
Leaving aside the updateTheArray function, even if I try to use the storage function in promise like this
var save = myStorage.put(array);
save.promise().done(function(){
console.log('blah');
});
I get a cannot read property promise of undefined error, so how do I make that storage return a promise object?
updateTheArray (finds a particular object in an array and changes a property)
function updateTheArray(array, attr, value){
var len = array.length;
len = len -1;
for (var i = len; i > 0; i --){
if(array[i][attr] === value) { //find by date
array[i]['completed'] = true; //set some property to true
}
}
}
storage
app.factory('myStorage', function(){
return {
get: function(){
return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
},
put: function(myarray){
localStorage.setItem(STORAGE_ID, JSON.stringify(myarray));
}
}
}
As described in this answer, local storage calls are synchronous, so there is no need to wait for myStorage.put to complete.
The reason for the cannot read property promise of undefined error is that you aren't returning anything at all from your put function on myStorage (but, as above, you don't need to return a promise anyway as it's a synchronous call).
The updateTheArray implementation you have shown is also synchronous, so the whole thing should work in order as-is, without any callbacks or promises required.

Listener for every array element

i've created an array. Each element is a button object. Is there a possibility to hook mouseclick on every array at the same time? I mean something like this.
var Objects:Array = new Array
Objects[0] = new button(parameters)
Objects[1] = new button(parameters)
Objects[2] = new button(parameters)
Objects[n].addEventListener(MouseEvent.CLICK, Clicked(n));
function Clicked(n,...)
{
THECODE PROCEEEEDS for Objects[n]
}
I know that's not the clearest and most correct writing, but I'm asking if this is possible in similiar way? And how to do it? I know I can hook every mouseclick and then check if the clicked under the mouse is one of the array elements with for loop, but I'm asking about this way.
Yes. You are unable to directly pass an index into a listener, but you can retrieve that via calling indexOf() inside it.
for each (b in Objects) b.addEventListener(MouseEvent.CLICK, clicked);
// note, you just put function name here!
public function clicked(e:MouseEent):void {
var i:int=Object.indexOf(e.target);
if (i==-1) {
// panic behavior
return;
}
// now you can parse that index into something valuable
}

Resources