Can Only Access One Class Variable from Checkbox Event - javascript

I'm sure this is a rookie error so forgive me since I'm new (this week) to AngularJS.
I've got an input which is a checkbox like below and it's hooked up to an ng-change event.
<input type="checkbox" ng-model="vm.hasCondoKey" ng-change="vm.onKeyCheckboxChange()" />
That^ event fires and runs the function "onKeyCheckBoxChange" in the controller.
export class CondoKeyController {
public condoKey: AdditionalItemModel;
public additionalItems: AdditionalItemModel[];
public hasCondoKey: boolean = false;
static $inject = ["$scope","CondoKeyService"];
constructor($scope: any, CondoKeyService: ICondoKeyService) {
$scope.additionalItems.forEach((addOn: AdditionalItemModel, index: number, addOnArray: AdditionalItemModel[]) => {
if (addOn.typeId === Models.AdditionalItemType.CONDO_KEY && addOn.quantity > 0) {
this.condoKey = addOn;
this.hasCondoKey = true;
}
});
}
public onKeyCheckboxChange(): void {
console.log("Checkbox changed.");
if(this.hasCondoKey === true) {
this.condoKey.typeId = AdditionalItemType.CONDO_KEY;
this.condoKey.quantity = 1;
if(!this.addOnsContainCondoKey()) {
this.additionalItems.push(_this.condoKey);
}
} else {
this.condoKey.quantity = 0;
}
}
}
The "CondoKeyController" is nested in a parent which passes the array "additionalItems" to this controller via a directive. I can see these other variables in other functions and when constructing the controller so they make it into this controller fine.
My problem is that in the function "onKeyCheckBoxChange" I can access "this.hasCondoKey" but I cannot access any of the other values such as "this.condoKey" or "this.additionalItems".
I was thinking that this had to do with the scope and context of my function since it came from a checkbox event but then I reasoned that I should not have access to the "this.hasCondoKey" value. This value reads as "true" from my breakpoints so it's been changed from its initialization value.
Does anyone know why I can access some variables and not others? Also how do I access the other variables?
Angularjs 1.6.6
Typescript ~2.3.1

Add some debug helping log to the method:
public onKeyCheckboxChange(): void {
console.log("Checkbox changed.");
console.log(this.condoKey);
console.log(this.additionalItems);
// ...
}
Check the result. It could be possible that condoKey and additionalItems are undefined, meaning they are never set.

Related

Binding a Vue property to an asynchronous value

I have a Vue block that I need to bind to a boolean property:
<div class="row" v-if.sync="isThisAllowed">
To calculate that property I need to make an API call using Axios, which has to be asynchronous. I've written the necessary code to get the value:
public async checkAllowed(): Promise<boolean> {
var allowed = false;
await Axios.get(`/api/isItAllowed`).then((result) => {
var myObjects = <MyObject[]>result.data.results;
myObjects.forEach(function (object) {
if (object.isAllowed == true) {
hasValuedGia = true;
}
})
});
return allowed;
}
What I did then - I'm not very experienced with Vue - is to add a property to the Vue model and assign a value to it in created:
public isThisAllowed: boolean = false;
async created() {
this.checkAllowed().then(result => {
this.isThisAllowed = result;
});
}
This works in the sense that the value I'm expecting is assigned to the property. But Vue doesn't like it and complains
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
Most of the values on the model are exposed via getters:
get isSomethingElseAllowed(): boolean {
return this.productCode === ProductTypes.AcmeWidgets;
}
But I need to "await" the value of the async function, which would mean making the getter async which then, of course, makes it a Promise and I can't bind that to my model?
What's the right way to go about this?
You can't define a property that way, instead define isThisAllowed in the data object
as
data: function(){
return {
isThisAllowed: false
}
}
And make checkAllowed into a normal function and set this.isThisAllowed = allowed inside it

How to pass js Object and functions to a web component

Hi All I am a beginner in javaScript and currently exploring JS Web-component and I got stuck due to some use cases
1 ) I want to pass a JS Object into my component like
<my-component data=obj ></my-component>
And require to use inside my component code Like
connectedCallback () {
console.log(this.data) // it should print {"name":"xyz" , "role" : "dev"}
}
2 ) I also need to pass some functions or maybe call back functions like.
function myFunction(e){
console.log(e)
}
<my-component click=myFunction ></my-component>
please try to add code snippet also in ans that will help me to learn more JS.
Thanks
You should pass large object by Javascript.
Via a custom element method:
let comp = document.querySelector( 'my-component' )
comp.myMethod( obj )
Or setting a property:
comp.data = obj
It is best to pass in complex data using a property and not an attribute.
myEl.data = {a:1,b:'two'};
The standard on events work fine on a custom element:
function myFunction(e){
alert(JSON.stringify(e.target.data));
e.target.data = {a:1,b:"two"};
}
class MyComponent extends HTMLElement {
constructor() {
super();
this._data = 0;
this.attachShadow({mode:'open'}).innerHTML="Click Me";
}
static get observedAttributes() {
return ['data'];
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
}
}
get data() {
return this._data;
}
set data(newVal) {
this._data = newVal;
}
}
customElements.define('my-component', MyComponent);
<my-component onclick="myFunction(event)"></my-component>
If your component dispatches a custom event then it is best to access it through code:
function specialEventHandler(evt) {
// do something
}
myEl.addEventListener('special-event;', specialEventHandler);
I did a Udemy course with Andreas Galster and the tutor passed in a JSON object via attribute.
As you can see it needs encodeURIComponent and decodeURIComponent as well to
attributeChangedCallback (name, oldValue, newValue) {
if (newValue && name === 'profile-data') {
this.profileData = JSON.parse(decodeURIComponent(newValue));
this.removeAttribute('profile-data');
}
this.render();
}
Pass in:
<profile-card profile-data=${encodeURIComponent(JSON.stringify(profile))}>
</profile-card>
The code worked fine for me.
Ad 1) You need to use JSON.stringify(obj)
Ad 2) As far as I know All attributes need to be defined as strings. You can pass the function that is global and inside component try to eval(fn)

Editing Boolean Function to Handle Lack of Value in Angular App

I have a function that's checking to see if a certain field in the API-revealed object has a value. The function returns a boolean. I am then styling some UI based on the result. The original function from the model looks like this:
public hasBillingCoverage(): boolean {
if (this.coverage[0].payer) {
return true;
} else if (!this.coverage[0].payer || this.coverage[0].payer === undefined) {
return false;
}
}
And I am using that in the component like this:
private hasCoverageBillingInfo() {
if (this.currentCustomer.hasFullName()) {
if (this.currentCustomer.hasBillingCoverage()) {
return true;
} else {
console.log('Coverage info not provided...');
return false;
}
}
}
The problem is, currently I'm getting an error in the console, that reads:
inline template:13:16 caused by: Cannot read property 'payer' of
undefined
That error points to this line in my component view:
<div class="page-content-header-item" [class.selected]="isSection('billing-and-coverage')" (click)="navigateTo('billing-and-coverage')"
[ngClass]="{'attention-needed': !hasCoverageBillingInfo()}">Billing and Coverage</div>
The above code in the view is designed to add some styling (the class "attention-needed') if the function "hasCoverageBillingInfo()" evaluates to false.
I thought I was already handling an undefined result, but apparently not. How can I edit this function so as to prevent the console error?

$onChanges doesn't get called when pushing an item to an array

Im using Angular 1.5.3 with typescript.
I have a outer and a inner component where the outercomponents holds an array named arrayValue which I pass to the innercomponent via <binding:
class InnerComponent {
controller: Function = InnerController;
bindings: any = {
arrayValue : "<"
};
...
}
The InnerController uses the $onChanges method to track any changes from one-way bindings (e. g. arrayValue):
public $onChanges(changes: any){
this.onChangesCalledCounter++;
console.log(changes);
}
If I now change the arrayValue within the outer component using:
public switchArrayValue(): void {
if(this.arrayValue === this.fruits){
this.arrayValue = this.vegetables;
} else {
this.arrayValue = this.fruits;
}
}
The $onChanges within the innercomponent gets called. However, If I change the switchArrayValue method to perform a push instead of a reassignment of the array, the $onChanges method won't get called:
public switchArrayValue(): void {
this.arrayValue.push("hello, world!");
}
Can anyone tell me why the push don't trigger the $onChanges and maybe show a workaround for that?
Here is a plnkr (that I forked).

AngularJS 1.5: scope.$watch inside link function doesn't update on model change

Good day to everyone!
I'm developing a web app, using typescript and angular 1.5;
I've created a directive the main goal of wich is to spy on whether user logged in or not, and hide/show corresponding element.
Here is the link function code:
interface ShowAuthedScope extends ng.IScope{
User: UserService,
_$log: ng.ILogService
}
function ShowAuthedDirective(User:UserService, $log:ng.ILogService) {
'ngInject';
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.User = User;
scope._$log = $log;
scope.$watch('User.current', function (val) {
scope._$log.log('updated!:', val);
})
}
}
}
The model for my case is the current user, that being set or unset depending on whether he is logged in or not.
here is the clipped code for the UserService:
interface UserInterface {
current:GoogleUser;
signIn(options?:SignInOptions):Promise<any>;
signOut():Promise<void>;
}
class UserService implements UserInterface {
public current:GoogleUser;
private _GoogleAuth:GoogleAuthService;
private _AppConstants;
constructor(GoogleAuth:GoogleAuthService, AppConstants) {
'ngInject';
this._GoogleAuth = GoogleAuth;
this._AppConstants = AppConstants;
this.current = null;
}
public signIn(options?:SignInOptions) {
let promise:Promise<any>;
let _options:SignInOptions = options || {};
_options.app_package_name = this._AppConstants.appPackageName;
if (this.current) {
promise = this.current.signIn(_options);
} else {
promise = this._GoogleAuth.signIn(_options);
}
promise = promise.then((googleUser:GoogleUser) => this.current = googleUser);
return promise;
}
public signOut() {
this.current = null;
return this._GoogleAuth.signOut();
}
}
The function inside $watch gets triggered only once after initializing;
Also note, that I already tried to pass true as the third parameter of the $watch function
Hope for your help! Thanks!
When you call signIn and signOut from the console, it happens outside something called a "Digest Cycle". Angular runs $watch statements in every digest cycle, but there needs to happen something that triggers it.
For example ng-click and all Angular event handlers automatically trigger digest cycle so that variable changes can be detected.
So in summary, if you want to do everything from the Console, you need to trigger digest cycle yourself:
angular.element(document).injector().get('$rootScope').$digest()

Categories