Angularjs function calls order - javascript

I have a dropdown list of options, which are shown or not depending on conditions.
<div class="col-sm-9">
<select class="form-control" ng-model="vm.templateType" ng-disabled="vm.status == 'sold' || vm.status == 'return' "ng-options="type.id as type.name for type in vm.templateTypes | filter:vm.isShowableTemplate"></select>
</div>
Here is my controller:
function FormOrderDialogController(tsModulesService, $scope, $q, $http, $uibModalInstance, params, $filter, Requester)
Requester.restGet("/events/" + params.eventId, null, params.serverId).then((data)=>{
vm.event = data;
});
Requester.restGet('/dic/10', null, null, null, true).then((resp) => {
vm.templateTypes = resp;
vm.templateType = vm.templateTypes[0].id;
});
vm.isShowableTemplate = isShowableTemplate;
function isShowableTemplate(templateType) {
switch (templateType.id) {
case 321:
return !!vm.event.info.ticketTemplate;
case 322:
return !!vm.event.info.ticketETemplate;
}
}
By the time isShowableTemplate is called I expect event object to be filled, And the thing is the getEvent function is called twice, once before isShowableTemplate get called, and once after. The problem is event is undefined after the first call and I get an error "Cannot read property 'info' of undefined".
My question is why is it so and what I am doing wrong. I am new to both js and angular, so may be I miss something essential.

Why not remove the function and filter:
function FormOrderDialogController(tsModulesService, $scope, $q, $http, $uibModalInstance, params, $filter, Requester)
Requester.restGet("/events/" + params.eventId, null, params.serverId)
.then(data => {
vm.event = data;
return Requester.restGet('/dic/10', null, null, null, true);
})
.then(resp => {
vm.templateTypes = resp;
vm.showableTemplateTypes = resp.filter(t => {
switch (t.id) {
case 321:
return !!vm.event.info.ticketTemplate;
case 322:
return !!vm.event.info.ticketTemplate;
}
return false; // or true depending if you want to show the others.
});
vm.templateType = vm.templateTypes[0].id;
});
}
I've combined the two Promises together because you use the vm.event in the second response. By doing it this way, you can always guarantee some value for vm.event.
The html:
<div class="col-sm-9">
<select class="form-control" ng-model="vm.templateType" ng-disabled="vm.status == 'sold' || vm.status == 'return' "ng-options="type.id as type.name for type in vm.showableTemplateTypes"></select>
</div>

Related

AngularJS scope values undefined but API is working fine

I don't get any error message, but while debugging Scope values are not binding it shows Undefined...
Controller:
$scope.companyModify = function () {
var param = {
companyId:$scope.companyId,
companyName:$scope.companyName,
billPrintLinesTop:$scope.billPrintLinesTop,
billPrintLinesBottom:$scope.billPrintLinesBottom,
isPrintHeader:$scope.isprintHeader,
billTypeId:$scope.billTypeId,
billColumnId :$scope.billColumnId,
noOfCopies: $scope.noOfCopies,
billHeaderAlignmentId: $scope.billHeaderAlignmentId,
billTitle: $scope.billTitle,
billSortOrderId:$scope.billSortOrderId,
posDefaultQty:$scope.posDefaultQty,
posTaxTypeId:$scope.posTaxTypeId,
isAllowNegativeStock:$scope.isAllowNegativeStock,
serviceTaxCalcTypeId : $scope.serviceTaxCalcTypeId,
wishMessage:$scope.wishMessage,
coinageBy:$scope.coinageBy,
isAutoGenerateProductCode:$scope.isAutoGenerateProductCode
};
console.log(param);
Calling the companyModify Function :
Open braces of companyModify closes in SocketService...
SocketService.post(apiManage.apiList['CompanyModify'].api,param).
then(function (resp) {
var data = resp.data.response;
if (data.status === true) {
angular.forEach($scope.companyList, function (value) {
if (value.companyId == $scope.companyId) {
value.$edit = false;
}
});
Notify.alert(data.message, {
status: 'success',
pos: 'top-right',
timeout: 5000
});
$scope.load();
}
else {
Notify.alert(data.message, {
status: 'danger',
pos: 'top-right',
timeout: 5000
});
}
});
};
Ensure $scope is properly injected in controller
someModule.controller('MyController', ['$scope', function($scope) {
...
$scope.aMethod = function() {
...
}
...
}]);
In your html code, input values are binded to company.XXX :
<input type="text" class="form-control input-sm" ng-model="company.posTaxTypeId" placeholder="Enter POSTaxCalculation" >
If you want your code to work is the controller, you must use the same binding and use posTaxTypeId: $scope.company.posTaxTypeId instead of posTaxTypeId: $scope.posTaxTypeId
or change your html code to :
<span data-ng-show="!company.isEdit" data-ng-bind="posTaxTypeId"></span>
<span data-ng-show="company.isEdit">
<input type="text" class="form-control input-sm" ng-model="posTaxTypeId" placeholder="Enter POSTaxCalculation" >
</span>
also ensure that binding are declared properly, without spaces :
bad
data-ng-bind="company.posTaxTypeId "
ng-model="company.posTaxTypeId "
good
data-ng-bind="company.posTaxTypeId"
ng-model="company.posTaxTypeId"

Ng-model did't show updated value until click somewhere on the page

All I want to do is to display the value of a ngModel, a variable defined in my controller. But the value didn't change to the correct value until I click somewhere else on the page or click the update button again. Although it does change to the correct value in the console.
My themeLayout.html file
<div class="theme-body" ng-controller="ThemeController as theme">
<select ng-model="theme.selectedTheme" ng-change="theme.getThemeDetails(theme.selectedTheme)">
<option ng-repeat="option in theme.themePacks">{{option.title}}</option>
</select>
<div class="form-group">
<label for="appLogo">App Logo</label>
<div>
<img ng-src="{{theme.currentThemeImageUrl}}" alt="Description" />
</div>
<input type="text" class="form-control" id="appLogo" ng-model="theme.currentThemeImageUrl">
</div>
</div>
And this is my theme controller
export default class ThemeController {
constructor($log, ApiService, $scope, $state, $window) {
'ngInject';
this.s3 = new this.AWS.S3();
this.selectedTheme = '';
this.currentThemeId = '';
this.currentS3ThemeOption = {};
this.currentS3ThemeOptionToUpload = {};
this.currentThemeImageUrl = '';
}
getThemeDetails(theme) {
this.$log.log(`get theme details function been called`, theme);
const obj = this;
for(let item of this.themePacks) {
if (theme === item.title) {
this.currentThemeId = item.themeId;
}
}
this.s3.getObject({
Bucket: `improd-image-pipeline`,
Key: `remoteUX/qa/${obj.currentThemeId}.json`,
}, (err, data) => {
if (err) {
obj.$log.log(err);
} else {
obj.currentS3ThemeOption = JSON.parse(data.Body);
obj.currentS3ThemeOptionToUpload = obj.currentS3ThemeOption;
for (const prop in obj.currentS3ThemeOption.colors) {
obj[prop] = obj.getColors(obj.currentS3ThemeOption.colors[prop]);
}
obj.currentThemeImageUrl = obj.currentS3ThemeOption.layout.titleImageUrl;
obj.$log.log(`We should have upadted theme opion now`, obj.currentS3ThemeOption, obj.currentThemeImageUrl);
}
});
this.$log.log(obj.currentS3ThemeOption, this.currentS3ThemeOption);
}
}
This is when I click the fox option in the selection, it read the data and stroe it into the currentSeThemeOption.
As you can see from the console, it also print of the value
What I am thingking is that might the 'this' and obj is causing the problem.
After I did add $scope.apply() function as he suggested, but it didn't solve the problem.
Update your model inside a scope.$apply() call:
getThemeDetails(theme) {
this.$log.log(`get theme details function been called`, theme);
const obj = this;
for(let item of this.themePacks) {
if (theme === item.title) {
this.currentThemeId = item.themeId;
}
}
this.s3.getObject({
Bucket: `improd-image-pipeline`,
Key: `remoteUX/qa/${obj.currentThemeId}.json`,
}, (err, data) =>
scope.$apply(() => {
if (err) {
obj.$log.log(err);
} else {
obj.currentS3ThemeOption = JSON.parse(data.Body);
obj.currentS3ThemeOptionToUpload = obj.currentS3ThemeOption;
for (const prop in obj.currentS3ThemeOption.colors) {
obj[prop] = obj.getColors(obj.currentS3ThemeOption.colors[prop]);
}
obj.currentThemeImageUrl = obj.currentS3ThemeOption.layout.titleImageUrl;
obj.$log.log(`We should have upadted theme opion now`, obj.currentS3ThemeOption, obj.currentThemeImageUrl);
}
})
);
this.$log.log(obj.currentS3ThemeOption, this.currentS3ThemeOption);
}
Once you have assigned a $scope object into the ng-model object. then you just put
$scope.$apply();
so that it will bind properly with UI elements.
It's the problem of digest cycle the digest cycle in triggered in only in four conditions
event (i.e your click),
http request,
change in input,
Timers with callbacks ($timeout etc.),

Don't have access to attribute in my controller Angular.js 1.3

I'm building a simple form.
This form get a birthday field.
I can select a date and persist it.
But when I reload the page, I have an error
Error: [ngModel:datefmt] Expected `2015-03-06T23:00:00.000Z` to be a date
I know how to resolve it. I need to convert my user.date_birthday to a Date.
So I tried this.
'use strict';
angular.module('TheNameApp')
.controller('SettingsCtrl', function ($scope, User, Auth) {
$scope.user = User.get();
$scope.errors = {};
console.log($scope.user); // display the resource
console.log($scope.user.date_birthday); //undefined
$scope.changeInformations = function(form) {
$scope.infos_submitted = true;
if(form.$valid) {
Auth.changeInformations({
gender: $scope.user.gender,
city: $scope.user.city,
country: $scope.user.country,
talent: $scope.user.talent,
date_birthday: $scope.user.date_birthday,
user_name: $scope.user.user_name,
email: $scope.user.email })
.then( function() {
$scope.infos_message = 'Done.'
})
.catch( function(err) {
err = err.data;
$scope.errors = {};
// Update validity of form fields that match the mongoose errors
angular.forEach(err.errors, function(error, field) {
form[field].$setValidity('mongoose', false);
$scope.errors[field] = error.message;
});
});
}
};
the .html
<div class="form-group">
<label>Birthday</label>
<input type="date" name="date_birthday" class="form-control" ng-model="user.date_birthday"/>
</div>
The user.date_birthday is not defined but I can see it in $scope.user
I need this for my next step
$scope.user.date_birthday = new Date($scope.user.date_birthday);
Why I can't see my attribute? How Can I resolve this?
Assuming your User is a resource, .get() is an async call. Use a callback:
User.get(function(user) {
user.date_birthday = new Date(user.date_birthday);
$scope.user = user;
});

Meteor method callback loop, what am I doing wrong?

I've been looking at this for awhile and I'm pretty sure it has something to do with an infinite callback loop.
I have a method that returns an integer from a collection called Sessions. Here are my methods:
Meteor.methods({
going: function(sessionsId) {
return Sessions.update(sessionsId, {$addToSet: {participants: Meteor.userId()}, $inc: {slots:-1}});
},
retract: function(sessionsId) {
return Sessions.update(sessionsId, {$pull: {participants: Meteor.userId()}, $inc: {slots:1}});
},
sessionFull: function(sessionsId) {
var session = Sessions.findOne({_id:sessionsId});
console.log("gets here");
return session.slots;
}
});
Then in my client I have:
if (Meteor.isClient) {
Template.hello.sessions = function () {
return Sessions.find();
};
Template.session.this_info = function () {
return this._id;
};
Template.session.isGoing = function() {
var session = Sessions.find({_id:this._id, participants:Meteor.userId()}).count();
if (session > 0) return true;
else return false;
};
Template.session.sessionFull = function() {
if (this.slots === 0) return true;
else return false;
};
Template.session.slotsMethod = function () {
Meteor.call('sessionFull',this._id, function(error, slots) {
Session.set("slots",slots);
});
return Session.get("slots");
};
Template.session.events({
'click input.going' : function () {
//Sessions.update(this._id, {$inc: {slots: -1}});
Meteor.call('going', this._id, function(error, updated) {
if (error)
return alert(error.reason);
});
},
'click input.retract' : function () {
Meteor.call('retract', this._id, function(error, removed) {
if (error)
return alert(error.reason);
});
}
});
So I basically have a couple buttons that will increase or decrease the slots field and I want to have a method that will return what the slots field contains. Here is my template:
{{#each sessions}}
{{> session}}
{{/each}}
<template name="session">
<br>
{{date_time}}, {{duration}}
{{#if isGoing}}
<input type="button" class="retract" value="not going/give slot" />
{{else}}
{{#if sessionFull}}
<h1>SORRY SESSION FULL</h1>
{{else}}
<input type="button" class="going" value="going/subract slot" />
{{/if}}
{{/if}}
{{participants}},{{sessionFull}},{{this_info}}
</template>
If I try to add the Template.session.slotsMethod to my template (which calls the sessionFull Meteor method) I get an infinite loop, as in, it will display a rapidly changing integer for each session.
Am I doing something wrong?? Can't figure it out, I think it has something to with callbacks/async/sync but not sure.
Yes, your Template.session.slotsMethod will cause an infinite loop since Session is reactive.
This is what happens:
Whenever Session.get("slots") changes, Template.session.slotsMethod will be called because its dependent on Session.get("slots").
However, Template.session.slotsMethod itself is also updating the value of Session.get("slots") so the process starts all over again.
Not quite sure when you want Template.session.slotsMethod to be run, but you probably want to break it up into two pieces, something like:
Template.session.getSlots = function () {
return Session.get("slots");
};
and
Meteor.call('sessionFull',this._id, function(error, slots) {
Session.set("slots",slots);
});
needs to go wherever/whenever you need to do the sessionFull check, perhaps in Template.session.rendered?

AngularJS: Taking old values instead of new during put

When updating, I want to insert new values coming from the ui instead of old values present in the local collection. The below code inserts old values in local collection(I don't want this to happen).
dataService.getSupplierById($routeParams.id)
.then(function (supplier) {
$scope.supplier = supplier; //now this contains local collection
$scope.save = function () {
$scope.updatedSupplier = $scope.supplier; //I want the scope to be updated and take values from the ui
dataService.updateSupplier($routeParams.id, $scope.updatedSupplier)
.then(function () {
//success
},
function () {
//error
});
};
},
function () {
//error
});
This is my Html.
<div>
<label for="City">City</label>
<input name="City" type="text" data-ng-model="updateSupplier.city" value="{{supplier.city}}" />
</div>
How can I do this? How can I update the scope to take new values? I'm new to angular.
If you are binding to updateSupplier as the ng-model then you shouldn't overwrite the values when you save:
$scope.save = function () {
// remove the line that overwrites, was here
dataService.updateSupplier($routeParams.id, $scope.updatedSupplier)
.then(function () {
//success
},
function () {
//error
});
};
}
Angular will take care of two-way binding the value inside the ng-model so by the time you save it will have the correct value that was input in the textbox.
You can also clean up the code by not have 2 different scope properties:
dataService.getSupplierById($routeParams.id)
.then(function (supplier) {
$scope.supplier = supplier; //now this contains local collection
$scope.save = function () {
dataService.updateSupplier($routeParams.id, $scope.supplier )
.then(function () {
//success
},
function () {
//error
});
};
},
function () {
//error
});
And then in the html:
<div>
<label for="City">City</label>
<input name="City" type="text" data-ng-model="supplier.city" />
</div>
The initial value should bind into the value attribute automatically.

Categories

Resources