AngularJS Controller Cannot Properly Invoke Function - javascript

I am using Angular 1.6 and am having trouble trying to get a controller to call a function I have passed in. In my example below, I have homepage.html which is passing a function into <image-selector>. I want <image-selector> to call the passed-in function which will update the parent when the image has been changed. HomepageCtrl will then call its own function updateState() to process the data.
The problem is that HomepageCtrl fails to call updateState() because this.updateState() in onImageChange() is undefined. I suspect that the issue is caused because ImageSelectorCtrl is invoking onImageChange() so this is pointed to the ImageSelectorCtrl instead of HomepageCtrl.
I am wondering how I would fix this issue so ImageSelectorCtrl can invoke onImageChange() which will then call updateState()?
// homepage.js
import homepageHtml from './homepage.html';
class HomepageCtrl {
constructor() {
}
onImageChange(newImage) {
this.updateState({newImage: processImage(newImage)}); // console error: cannot read property of 'updateState' of undefined
}
updateState(options) {
console.log('Updating state...');
}
}
export const Homepage = {
template: homepageHtml,
controller: HomepageCtrl
};
// homepage.html
<div class="homepage">
<image-selector on-change="$ctrl.onImageChange"></image-selector>
</div>
// imageSelector.js
import imageSelectorHtml from './image-selector.html';
class ImageSelectorCtrl {
constructor() {
this.imageUrl;
}
onChange() {
this.onChange()(imageUrl);
}
}
export const ImageSelector = {
bindings: {
onChange: '&'
},
template: imageSelectorHtml,
controller: ImageSelectorCtrl
};

please try binding this to your class methods as they are being executed in a different context.
class HomepageCtrl {
constructor() {
this.onImageChange = this.onImageChange.bind(this)
this.updateState = this.updateState.bind(this)
}
onImageChange(newImage) {
this.updateState({newImage: processImage(newImage)}); // console error: cannot read property of 'updateState' of undefined
}
updateState(options) {
console.log('Updating state...');
}
}

Related

StimulusJS How to set an instance variable on connect

I am trying to get into stimulusJS
import { Controller } from 'stimulus'
export default class extends Controller {
static targets = [
'foo',
]
connect() {
const fooValue = this.fooTarget.value
console.log(this.fooValue) // 7
this.someFunction()
}
someFunction(){
console.log(this.fooValue) // undefined
}
}
I want to be able to get this value on connect as I want to know if it has changed.
Your code declares const variable within the scope of connect() function. But you should use this (Stimulus Controller) property instead:
...
connect() {
this.fooValue = this.fooTarget.value
...

AngularJS - Multiple inheritance to call a controller variable from a service

I have a sample service:
export class ProjectActionService extends ActionService {
constructor() {
'ngInject'
super($state)
}
getProjects() {
// Call API...
}
}
I would like to change the value of a variable (this.showLoader) that exists in a controller from the getProjects () method.
Controller:
export class ProjectComponent {
constructor() {
'ngInject'
}
$onInit() {
this.showLoader = false
}
}
what is the best way to do it, with a multiple inheritance (mixin), a directive ...?
This is not an appropriate way to deal with it. Your service method should only call the api and get the data and not change controller variables. One way to show/hide loader is changing the boolean before calling and change again after getting the response. A sample inside controller after injecting you service:
this.showLoader = true;
this.ProjectActionService.getProjects().then(response => {
...
})
.finally(() => this.showLoader = false);

Calling a function from a controller to another controller in AngularJS

Having this controller:
class FirstController{
constructor(){
...
}
$onInit(){
}
updateField(name) {
...
this.callback({id: name});
}
}
const firstController={
bindings: {
site: '<',
callback: '&'
},
controller:FirstController,
templateUrl:require('./FirstController.html')
};
export default firstController;
I want to call the callback() method into another one, so I did it like this:
import firstController from './../core/firstController/firstController.js';
class SecondCtrl {
constructor(SecondService, ...) {
reset() {
firstController.callback();
...
}
}
It doesn't work, I get this error message:
Uncaught ReferenceError: firstController is not defined
Any suggestions?

Vue creating a plugin

I feel a bit like I'm missing something very simple, but I've been trying different stuff out and searching all over the place and can't figure out how to use a method from a custom plugin in my Vue application.
In 'vuePlugin.js' I have something like:
const myPlugin = {};
myPlugin.install = function(Vue, options){
Vue.myMethod = function(){
console.log("It worked!");
}
}
In my main.js I have:
import myPlugin from './js/vuePlugin.js'
Vue.use(myPlugin);
Then in my App.vue I have:
export default {
name: 'app',
props: {},
data () {
return{ someData: 'data' }
},
beforeCreate: function(){
myMethod();
}
}
With this I get an error that "myMethod is not defined".
I've tried saying:
var foo = myPlugin();
console.log(foo);
In my console I get an object called "install" with arguments:
"Exception: TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context. at Function.remoteFunction"
All of the documentation seems to just show how to create the plugin and "use" it, but not actually how to access anything in it. What am I missing here?
You have to export your object to be used in vuejs as follows
file vuePlugin.js
const myPlugin = {}
myPlugin.install = function (Vue, options) {
Vue.myMethod = function () {
console.log('It worked!')
}
Vue.prototype.mySecondMethod = function () {
console.log('My second Method ')
}
}
export default myPlugin
while calling the method you cannot call the method directly, you have to use as following code shown
file App.vue
export default {
name: 'app',
props: {},
data () {
return{ someData: 'data' }
},
beforeCreate: function(){
Vue.myMethod(); // call from Vue object , do not directly call myMethod()
this.mySecondMethod() // if you used prototype based method creation in your plugin
}
}
hopes it will help you

Injected module is undefined when calling module function

I'm trying to make a website where i use Aurelia and Javascript and ES6.
I have a simple class (Status) that needs to get some data on a interval from a server.
Update
I have added CalcData to the injector as sugessted by Fabio Luz, but i still get the same error. Good call btw ;).
The class looks like this:
import {inject} from "aurelia-framework"; // for the inject decorator
import { StatusData } from "./statusData"; // MovieData, the module that will be injected
import { CalcData } from "./Calc"
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(StatusData, CalcData) {
this.statusData2 = StatusData;
this.CalcData = CalcData;
}
activate() {
setInterval(this.updateCalc, 3000);
}
updateCalc() {
this.CalcData.hello()
.then(statusData => this.statusData2 = statusData);
}
updateStatus() {
return statusData2.getX()
.then(statusData => this.statusData2 = statusData);
}
update() {
return 1;
}
}
The updateCalc function is called but when this happens the browser says it that CalcData is undefined.
Uncaught TypeError: Cannot read property 'hello' of undefined
at updateCalc (status.js:17)
updateCalc # status.js:17
status.js:17 Uncaught TypeError: Cannot read property 'hello' of undefined
at updateCalc (status.js:17)
updateCalc # status.js:17
The CalcData class looks like this:
import { inject } from "aurelia-framework"; // for the inject decorator
import { HttpClient } from "aurelia-http-client"; // for the http client that will be injected
let baseUrl = "/movies.json";
#inject(HttpClient)
export class CalcData {
constructor(httpClient) {
this.http = httpClient;
}
hello() {
return this.http.get(baseUrl)
.then(response => {
return response.content;
});
}
}
I can't seem to find the problem, i have looked around but can't find a solution. I must say that i'm new to Aurelia.
Any help is much appreciated!
Your problem is down to capitalization, most likely.
Let's look at the beginning of your code:
import {inject} from "aurelia-framework"; // for the inject decorator
import { StatusData } from "./statusData"; // MovieData, the module that will be injected
import { CalcData } from "./Calc"
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(StatusData, CalcData) {
this.statusData2 = StatusData;
this.CalcData = CalcData;
}
Notice that your constructor is taking parameters whose names exactly match the names of the classes you want to inject. This is causing confusion for the runtime, as you are likely ending up setting this.Calcdata to the class CalcData (and the same for StatusData). The class does not have a function called hello(), only instances of the class have that function. If you change the parameter names to not exactly match, your issues should go away.
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(statusData, calcData) {
this.statusData = statusData;
this.calcData = calcData;
}
I've also lower-cased the property names to match JavaScript naming conventions.
Seems like i had to bind "this" to pass the object reference. When calling this in hello it how read gets the right object.
E.g.
import {inject} from "aurelia-framework";
import {StatusService} from "./statusService"
#inject(StatusService)
export class Status{
message = 'unknown yet';
statusService: StatusService;
constructor(statusService){
this.statusService = statusService;
}
activate(){
setInterval(this.updateStatus.bind(this), 3000);
}
updateStatus = function () {
this.message = this.statusService.getX();
}
}

Categories