Game in Phaser - JavaScript and Events in AngularJS - javascript

How can I execute an AngularJs method from plain javascript?
myApp.controller("someController",["$scope",function($scope){
//Some code was here
$scope.a = valueA;
$scope.b = valueB
});
And a bit later in the code want to execute a function that when valid could execute an IF and if thats the case will execute my AngularJS controller or what ever.
function Clicked(){
if( was clicked correctly ){
//execute my Controller and send some data to add to the DOM
}
I don't want my HTML elements to trigger a function inside your controller.
I know I can build up my canvas from my AngularJS controller and then, since I'm inside the controller, I will have more easy access to it. But, I wanted to know if there is anyway I could executed from the outside of Angular so I could leave my controller light and simple.
Because; what I want to do it's to connect a small game I have in Phaser Framework with some external elements that I have made in AngularJS. Think about it like a TV just that the bottoms and controllers are in Phaser and the Screen it's the Angular part. So basically when something happens in the Phaser part I want to communicated to the Angular part.

Finally I have a solution,
var intermediary;
myApp.controller("someController", ["$scope",function($scope){
intermediary = function(fn){
var phase = $scope.$root.$$phase;
var value;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
value = fn();
if(value){
$scope.valIntermediary = value;
}
}
} else {
$scope.$apply(function() {
value = fn();
if (value) {
$scope.valIntermediary = value;
}
});
}
};
$scope.$watch("valIntermediary",function(){
//Do something whit a value var inside my controller
});
}]};
if(intermediary){
intermediary(function(value) {
return { /*Some data when click is true*/}
})
}

Related

Call method inside function

i have a wizard from a metronic theme where I'm trying to call a function to check if my array contains dublicates.
if I remove this part of my code it works without problems.
console.log(this.checkIfArrayIsUnique());
code
var wizard = (<any>$('#m_wizard')).mWizard();
//== Validation before going to next page
wizard.on('change', function(wizard) {
if(wizard.getStep() > 2){
console.log(this.checkIfArrayIsUnique());
}
mApp.scrollTop();
})
Right now my checkIfArrayIsUnique() is just a dummy function
checkIfArrayIsUnique()
{
return true;
}
how can i call a method outside my 'change' event ? So I'm able to run thru my array and confirm it does not have any dublicates.
the problem is the "function(wizard)" call, since it creates a new scope. But your checkIfArrayIsUnique() ist actually outside of this scope.
Try using ES6 function syntax
wizard.on('change',(wizard) => {
if(wizard.getStep() > 2){
console.log(this.checkIfArrayIsUnique());
}
mApp.scrollTop();
})
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
in your change function the variable this point to current function,to use it,you should make this point to out object,you should write like this:
var that = this;
var wizard = (<any>$('#m_wizard')).mWizard();
//== Validation before going to next page
wizard.on('change', function(wizard) {
if(wizard.getStep() > 2){
console.log(that.checkIfArrayIsUnique());
}
mApp.scrollTop();
})

Data binding between controller and service in angularJs

I want to know the correct way to do the following, I have a service, a factory, and a controller.
The service has a selectedTable property that starts as null by default and it's used to store the selected table in order to be used in both the factory and the controller; the service also has a touches property that it's updated regularly in the factory and the controller, that service looks like this:
Module.service('tablesService', function(){
this.data = {
selectedTable: null,
touches: 0
}
});
The factory uses the service by setting up a variable var data = tablesService.data and has a method select that modifies the value of data.selectedTable and data.touches:
if (data.selectedTable === this){
data.touches++;
if (data.touches === 2) {
data.selectedTable = null;
}
} else {
if (data.selectedTable && data.selectedTable != this) {
data.touches++;
data.selectedTable.select();
}
data.selectedTable = this;
}
The controller looks in a list of tables on every onClick event and when it founds the clicked table calls it's select() method, the one in the factory, if the table clicked is the selectedTable, it changes the touches variable so when it's select() method it's called, the selectedTable get's null as the new value.
$scope.tablesData = tablesService.data;
$scope.selectedTable = $scope.tablesData.selectedTable;
$scope.touches = $scope.tablesData.touches;
$scope.findTable = function(event){
$scope.touches = 0;
for(t in $scope.tables) {
var table = $scope.tables[t];
var result = table.findMe(event.offsetX,event.offsetY);
if(result.type === 'table') {
if ($scope.selectedTable === table){
$scope.touches++;
}
table.select();
break;
}
}
The problem is that changing $scope.touches won't update the variable in the service and vice-versa, this also happens with the selectedTable, I tried using $watch on both $scope.touches and $scope.tablesData.touches but the $digest() method doesn't fire up every time I change $scope.touches so I have to call $apply() which looks awful and doesn't solve the problem all the time.
My watchers look like this:
$scope.$watch('touches', function(){
$scope.tablesData.touches = $scope.touches;
});
$scope.$watch('tablesData.touches', function(){
$scope.touches = $scope.tablesData.touches;
});
Reading this post http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/ I found out that I can broadcast an event to the application via $rootScope.$broadcast(), but I'm not really sure how to implement that and perhaps that's not the best way to solve the problem.

What happens behind the scenes when binding to a function in AngularJS

Can anyone explain what happens behind the scenes when you bind to a function in AngularJS? What kind of watch does it create? I have a feeling it would create two watches (in my example below) one for each property that makes up the return value. However I'm certainly not sure about this but it feels like something we shouldn't do.
e.g.
<div ng-show="vm.someFunc()">
JS
vm.someFunc = function() {
return vm.property1 || vm.property2;
}
If you created the angular scope method "vm.someFunc()", this will continuously get polled. You can verify this by setting a breakpoint in this method, it will continuously keep getting hit. If you check the task manager and show the browser running your website, the memory keeps going up and won't stop.
In my opinion, scope functions should only be used when using event triggers: click event, change event, keypressed are some of the examples.
Showing or hiding aren't events, so this is why it gets polled like that.To fix and provide the same functionality, turn this into a scope variable.
change the html tag from:
<div ng-show="vm.someFunc()">
to
<div ng-show="vm.someFunc">
And in your controller:
$scope.KeyPressed = false;
$scope.Tags = '';
then create a watch event on what you want to watch for:
//initialize showtag when page loads
$scope.vm.someFunc = $scope.KeyPressed && $scope.Tags !== '';
//watch for any new changes on keypressed
$scope.$watch('KeyPressed', function (newValue, oldValue) {
if (newValue && $scope.Tags !== '') {
$scope.vm.someFunc= true;
} else {
$scope.vm.someFunc= false;
}
}
//watch for any new changes on keypressed
$scope.$watch('Tags', function (newValue, oldValue) {
if (newValue !== "" && $scope.KeyPressed) {
$scope.vm.someFunc= true;
} else {
$scope.vm.someFunc= false;
}
}
Or you can change to a "watchCollection" instead of having multiple watches like:
$watchCollection('[KeyPressed, Tags]', function (newValue) { }
newValue[0] is the value of KeyPressed, and newValue[1] is the value of Tags
Or to go along with the accepted answer and minimize the amount of watches:
$scope.TruthyVal= function () {
return $scope.KeyPressed && $scope.Tags !== '';
};
$scope.$watch('TruthyVal', function (newValue, oldValue) {
if (newValue) {
$scope.vm.someFunc= true;
} else {
$scope.vm.someFunc= false;
}
}
In fact angular does not care what you write in html - function, variable or whatever. It takes expression as string, parse it and calculate its value each digest cycle. So, {{1 + 2}} and {{sum(1, 2)}} and {{1 | sum:2}} are actually doing same job at more or less same speed.
All three ways are legit and do not create memory leaks.
The reason why it is always not recommended to use functions in ng-show is that lot of functions are time consuming, so your digest becomes very slow. And even if your functions are fast, you are not guaranteed that they wont grow up in future.

Sub-viewmodels in Knockoutjs

Well met!
I am playing around with Knockoutjs with the goal of having a single ViewModel, which controls multiple sub-viewmodels. This in order to have more control over the views itself and to prevent putting various parts of my view into their own little place. The code below should explain my idea:
ApplicationViewModel
ApplicationViewModel = function () {
var self = this;
// Context (for laziness' sake, no separate VM)
self.activeProject = ko.observable();
// States
self.projectsLoaded = ko.observable(false);
// State-change events
// Let application know that loading of projects has been called
self.projectsLoaded.subscribe(function (newValue) {
if (newValue === true) {
console.log('Projects have loaded');
} else {
console.log('Projects have not loaded');
}
});
// Let application know that selection of a project has happened
self.activeProject.subscribe(function (newValue) {
if (newValue != null) {
// Notify other viewmodels that a project has been (successfully loaded)
// Use hook-pattern to hook into this event
} else {
// Notify something went wrong- present user with a notification
// Application stops processes that are project-dependant
}
});
self.ProjectViewModel = new ProjectViewModel();
};
ProjectViewModel
ProjectViewModel = function () {
var self = this;
self.projects = ko.observableArray();
self.loadProjects = function () {
// Business logic to retrieve projects, think AJAX
var placeHolderProjects = [];
// Find projects somewhere and load them up!
// If something went wrong, notify parent
if (placeHolderProjects.length > 0) {
self.projects(placeHolderProjects);
$root.projectsLoaded(true);
} else {
$root.projectsLoaded(false);
}
};
self.selectProject = function (projectId) {
if (!projectId) {
$.parent.activeProject = null;
return;
}
// Fetch data for project, stuff like membershipId
var loadProjectResult = magicalLoadFunction(projectId);
if (loadProjectsResult === true) {
$root.activeProject(projectId);
} else {
$root.activeProject(projectId);
}
// Exit
return;
}
/********** Constructor logic
****************************/
self.loadProjects();
};
So basically, what I am looking for, is a way to:
- Control parent/child properties from their respective child/parent inside the viewmodels.
I am looking into AngularJS as well, but I'd really like to get this working in KnockoutJS first :) Immediate problem, is that I can't get $root/$parent to work. I bind the ApplicationViewModel in a $(document).ready() handler, unsure if I have to actually bind the sub-viewmodels to the view as well. I have bound ApplicationViewModel to the body element.
Thanks for reading and, possibly for answering/helping me get on my way :)
The answer provided by #jansommer proved successful.
I changed the following line (added this as a parameter):
self.ProjectViewModel = new ProjectViewModel(this);
And that was what was needed.
Thanks!

Moving logic to a service in Angular

I've ended up with a lot of logic in my controller which I realise is not good. Therefore I would like to move this to a service.
At the moment the controller accepts a url which will either be from YouTube or Vimeo. It detects whether the string "youtube" or "vimeo" is present in the url and then does what it needs to do accordingly. Here's part of the "logic" that currently resides in the controller:
if url.indexOf("youtube") > -1 {
variable_1 = "Something";
variable_2 = "Something";
//do some more stuff
}
else {
variable_1 = "Something";
variable_2 = "Something";
//do some more stuff
}
$scope.task.items.push("I need to add things to this array too");
A Service is the way to go but my first question is a service or a factory?
This is what I'm working on but I'm not sure how I would pass the variables that exist in the controller (variable_1 and variable_2) back to the controller when the service has completed.
myApp.service('urlService', function() {
this.detectProvider = function() {
if url.indexOf("youtube") > -1 {
}
else {
}
//how can I push things to the $scope array here?
};
});
In your service
myApp.service('urlService', function() {
this.detectProvider = function(url) {
arrayOfMyVars = new Array();
if url.indexOf("youtube") > -1 {
arrayOfMyVars.push("Something");
arrayOfMyVars.push("SomethingElse");
}
else {
arrayOfMyVars.push("Something");
arrayOfMyVars.push("SomethingElse");
}
//how can I push things to the $scope array here?
return arrayOfMyVars;
};
});
in your controller
var res = urlService.detectProvider(url);
variable_1=res[0];
variable_2=res[1];
$scope.task.items.push('the thing you need to push'); // maybe res[2] and in your service you had another arrayOfMyVars.push('the thing you need to push')...
Don't forget to import your service into your controller ;)
A Service is the way to go but my first question is a service or a
factory?
Simply speaking it does not matter. From personal point of view just use what suits you best. A service will create a new instance of the function, a factory will simply execute the function and do not create a new instance of it.
About your second question: Simply return variable_1 and variable_2 in your services method and assign them to your $scope.
myApp.service('urlService', function() {
this.detectProvider = function(url) {
if url.indexOf("youtube") > -1 {
...
return [variable_1, variable_2];
}
else {
...
return [variable_1, variable_2];
}
};
});
Service or Factory both are singleton instances. At the end u will get object only.
In service you will create using functtion constructor
In Factory we can construct it using object literrals

Categories