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?
Related
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);
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...');
}
}
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
I am trying to create directive in Typescript which will keep watch on pending $resource requests. I want only one directive as an attribute which will be used with div in index.html to show loading progress. Below is my code for directive.
module app.common.directives {
interface IProgressbarScope extends ng.IScope {
value: number;
isLoading: any;
showEl: any;
}
class Progressbar implements ng.IDirective {
static $inject = ['$http'];
static instance(): ng.IDirective {
return new Progressbar;
}
//transclude = true;
restrict = 'A';
replace = true;
link = function (scope: IProgressbarScope, elements: ng.IAugmentedJQuery, attrs: ng.IAttributes, $http: ng.IHttpService) {
debugger;
scope.isLoading = function () {
return $http.pendingRequests.length > 0;
};
scope.$watch(scope.isLoading, function (v) {
debugger
if (v) {
elements.addClass("hidediv")
} else {
elements.removeClass("hidediv");
}
});
}
}
angular.module('app')
.directive('progressbar', Progressbar.instance);
}
in Index.html, it is used as below:
<div progressbar id="myProcess" name="myProcess">
// loading image
</div>
But in directive, $http is always undefined. Note that I am not using $http directly. I a using $resource service for making server side api requests.
The reason $http undefined is, you are trying to get $http dependency from link function of directive. Basically 4th parameter of link function stands for require controller.
You should Ideally get that injected dependency instance from Progressbar constructor function.
class Progressbar implements ng.IDirective {
_http: ng.IHttpService; //defined _http variable
static $inject = ['$http'];
//asking for dependency here
static instance($http: ng.IHttpService): ng.IDirective {
this._http = $http; //get `$http` object assigned to `_http`
return new Progressbar;
}
//transclude = true;
restrict = 'A';
replace = true;
//removed dependency from here
link = function (scope: IProgressbarScope, elements: ng.IAugmentedJQuery, attrs: ng.IAttributes) {
//use arrow function here
scope.isLoading = ()=> {
return this._http.pendingRequests.length > 0;
};
//use arrow function here
scope.$watch(scope.isLoading, (v)=> {
if (v) {
elements.addClass("hidediv")
} else {
elements.removeClass("hidediv");
}
});
}
}
define $scope.isLoading inside directiveController and make $http call from service layer.
basic controller.ts
export class sampleController {
// inject service here
constructor() {
}
public isLoading() {
callServiceFunction();
}
}
sampleController.$inject['service'];
Import this controller inside custom directive.
SampleService.ts
export class sampleService {
constructor() {
}
}
sampleService.$inject = ['$http'];
Register this service inside app module.
For more info refer sample Importing and exporting example and large scale app architecture
I have the following code as my controller...
module scrumtool.app.Controllers {
export class ConfigController implements Directives.IConfigScope{
static $inject = [
"$scope"
];
public message: string = "Testing";
constructor() { }
clickMe = () => {
return this.message;
}
}
}
The IConfigScope interface is defined as such under the directives module for the time being...
export interface IConfigScope {
message: string;
clickMe(): string;
}
The directive is then like so...
module scrumtool.app.Directives {
export interface IConfigScope {
message: string;
clickMe(): string;
}
export class Cog implements ng.IDirective {
restrict: string = "A";
controller = Controllers.ConfigController;
constructor($scope: Directives.IConfigScope) {
}
link = function($scope: Directives.IConfigScope, element: ng.IAugmentedJQuery,
attr: ng.IAttributes, ctrl: Controllers.ConfigController) {
element.on("click", (e) => {
alert(ctrl.clickMe());
});
}
static factory(): ng.IDirectiveFactory {
var directive: ng.IDirectiveFactory =
($scope: Directives.IConfigScope) => new Cog($scope);
directive.$inject = [];
return directive;
}
}
}
Essentially I was able to make this work. What I don't understand is that through the $scope variable I can access the message variable and have it alert the message "Testing".
What I can't quite understand is why I can't simply say:
alert($scope.clickMe());
and have it return the message. When I attempt the above I get undefined.
Can someone please explain this to me?
Dependencies defined inside of the:
static $inject = [
"$scope"
];
must be somehow delivered, injected. The way with angular is via constructor. So we need this:
// there is no param in constructor, to be used
// constructor() { }
// but we need one - $scope
constructor(protected $scope) { }
we also should provide a type of passed $scope
constructor(protected $scope:IConfigScope) { }
which will mean, that the passed $scope would have these messages and clickMe implemented.
Other words - controller won't implement IConfigScope, it will be provided with that
But if we want to let our controller do that job, we should use controllerAs syntax
export class Cog implements ng.IDirective {
restrict: string = "A";
controller = Controllers.ConfigController;
controllerAs = "Ctrl";
...
and later anywhere inside of view template we can use
{{Ctrl.messages}}
...
ng-click="Ctrl.clickMe()"