Why I dont get array in template? - angularjs

I have ng-click method showSchedules() that calls AJAX:
$scope.showSchedules = function () {
$scope.loadCalendar = true;
appointmentService.getSchedule().then(function (response) {
calendarService.set(response.data.calendar, function () {
$timeout(function () {
$scope.refleshCalendars();
$scope.loadCalendar = false;
console.log($scope.events);
}, 100);
});
});
};
Inside this method you can see: console.log($scope.events);
It gives me filled array by objects.
When I do {{events}} in trmplate HTML I get [].
Why I get empty array?
HTML code:
<div ng-controller="ScheduleController as vmx">
{{events}}
<mwl-calendar
events="events"
view="vmo.calendarView"
view-title="vmo.calendarTitle"
current-day="vmo.calendarDay"
on-event-click="vmo.eventClicked(calendarEvent)"
on-event-times-changed="vmo.eventTimesChanged(calendarEvent);
calendarEvent.startsAt = calendarNewEventStart;
calendarEvent.endsAt = calendarNewEventEnd"
auto-open="true"
day-view-start="06:00"
day-view-end="23:00"
day-view-split="30"
cell-modifier="vmo.modifyCell(calendarCell)">
</mwl-calendar>
</div>

You want {{vmx.events}} because you are using the controller as annotation
Using controller as makes it obvious which controller you are
accessing in the template when multiple controllers apply to an
element.
ngController documentation (Search for controller as)

Related

AngularJs Component and angularjs-dropdown-multiselect

I am new to AngularJs world and was trying to use angularjs-dropdown-multiselect inside component.
Component's HTML looks like:
<div>
<select id="statusSelection" class="form-control"
ng-options="status.name for status in $ctrl.statuses track by status.id"
ng-model="$ctrl.status" ng-change="$ctrl.filterChanged()"></select>
</div>
<div ng-dropdown-multiselect="" options="$ctrl.categories" selected-model="$ctrl.category"
events="$ctrl.events">
</div>
Event on status changed and category will call the same action.
MultiselectController.prototype.filterChanged = function() {
this.onFilterChange({
status: this.status,
category: this.category});
};
MultiselectController.prototype.events = {
onItemSelect: function(item) {
filterChanged();
},
onItemDeselect: function(item) {
filterChanged();
}
};
When I try to run the above code and change the status, the code works as expected but fails during Category change(error in console).
Error message: ReferenceError: filterChanged is not defined
Angular version: 1.5.8
angularjs-dropdown-multiselect: 1.11.8
Plunker: http://plnkr.co/edit/JL7N6M?p=preview
Thanks for helping me out here.
I have created an instance variable and initialize it to instance of Controller.
var _instance;
function MultiselectController($scope) {
this.statuses = testMultiselect.statuses;
this.categories = testMultiselect.categories;
this.$scope = $scope;
this.setDefault();
_instance = this;
}
Now, I am using this instance variable to access the functions on Controller.
MultiselectController.prototype.events = {
onItemSelect: function(item) {
_instance.filterChanged();
},
onItemDeselect: function(item) {
_instance.filterChanged();
}
};
I am not completely happy with this as there should be better way to do the same but until I find, I will keep this.
Updated Plunker: http://plnkr.co/edit/D7BKI9?p=preview

ReCaptcha Google data-callback with angularJs

I have implemented google Captcha in my angularjsApp.
I have this HTML
<div class="g-recaptcha" data-sitekey="{{key}}" data-callback="enableBtn()"></div>
And in my controller I have:
$scope.enableBtn = function(){
$scope.captchaSigned = true;
};
$scope.key = "xyz";
But not working and in my console return :
ReCAPTCHA couldn't find user-provided function: enableBtn()
How can I make a data-callback with Angularjs?
In your html put :
<div class="g-recaptcha" data-sitekey="{{key}}" data-callback="enableBtn"></div>
And in your controller, put :
var enableBtn = function(){
$scope.captchaSigned = true;
};
$scope.key = "xyz";
window.enableBtn = enableBtn;
This should work as it will bind the function in controller.
I have resolved with this library https://github.com/VividCortex/angular-recaptcha
In Controller :
window.wrongCaptchaResponse = true;
window.recaptchaResponse = function(key) {
window.wrongCaptchaResponse = false;
};
In HTML page:
<button type="submit" ng-disabled="loginForm.$invalid || wrongCaptchaResponse">Login</button>
You can initialize recaptcha in your angular controller. eg.
inside your controller add this on a button click or initialize or timeout if you need it on page load. :
function showRecaptcha(){
if(typeof grecaptcha !='undefined'){
grecaptcha.render('register-recaptcha', {
'sitekey' : 'your_site_key',
'callback' : recaptchaCallback,
});
}
}
function recaptchaCallback(resp){
console.log(11,resp);
}
<div id="register-recaptcha"></div>
instead of $scope.enableBtn = function(){ define your function as window.enableBtn = function(){
Ensure you use data-callback="enableBtn" and NOT data-callback="enableBtn()"

AngularJS ng-click doesn't work in digest cycle

Html:
<a href id="link "ng-click="print(arg)"> print </a>
Angularjs controller:
$scope.return_promise =function(arg){
return $http.post('\path');
)};
$scope.print = function(arg){
url ="other/path/"
$scope.return_promise(arg).then(function(r){
if(r){
$('#link').attr('href', url);
});
};
Problem: I checked with chrome debugger, the href actually updated, but the event doesn't trigger (i.e. not go to the url). If I click it again, it works.
If I add a statement document.getElementById('#link').click() at the end of if clause, it will prompt an error "digest cycle is in progress"
How can i solve this.
Not sure if I get your question. First, check if the code you paste is the code you wanted add here, because it has numerous errors. If you would like to replace dynamically href attribute do it like so:
<div ng-controller="SomeCtrl as ctrl">
print
</div>
(function () {
'use strict';
angular
.module('module')
.controller('SomeCtrl', SomeCtrl);
SomeCtrl.$inject = ['$scope'];
function SomeCtrl($scope) {
var vm = this;
vm.url = "#";
vm.return_promise = function (arg) {
return $http.post('/path');
};
vm.print = function (arg) {
var url = "other/path/";
vm.return_promise(arg).then(function (r) {
if (r) {
vm.url = url;
}
});
};
}
}());

Accessing directive scope in controller using service

I was trying to access a value returned by a directive in my controller. I tried with a service. It's not working; it seems like the updated directive's return value is not picked up by the controller.
Here's my code:
HTML
<html ng-app="myApp">
<body ng-controller="MainCtrl">
<input type="file" file-reader="fileContent" />
<div>{{fileContent}}</div>
</body>
</html>
Controller
myApp.controller('MainCtrl', function($scope,sharedTrialService) {
$scope.newValue = sharedTrialService.TrialInfo;
$scope.newData = $scope.newValue.data;
});
Directive
myApp.directive('fileReader', function(sharedTrialService) {
return {
scope: {
fileReader:"="
},
link: function(scope, element) {
$(element).on('change', function(changeEvent) {
var files = changeEvent.target.files;
if (files.length) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result.replace(/\r\n|\r/g,'\n');
scope.$apply(function () {
var lines=contents.split('\n');
scope.fileReader = lines;
sharedTrialService.TrialInfo.data=scope.fileReader;
});
};
r.readAsText(files[0]);
}
});
}
};
Service
myApp .factory('sharedTrialService', function () {
return {
TrialInfo: {
data: " "
}
};
})
});
How can I access the directive's sharedTrialService.TrialInfo.data from my controller?
With $scope.newValue = sharedTrialService.TrialInfo.data; you are just assign a string to newValue, but you need to assign a reference, so you need to assign an object or an array. So change it to $scope.newValue = sharedTrialService.TrialInfo; and access your data via newValue.data.
EDIT
Use $watch in your controller for debugging:
$scope.$watch('newValue', function() {
console.log('newValue:', $scope.newValue);
}, true);
$scope.$watch('newData', function() {
console.log('newData:', $scope.newData);
}, true);
I think, $scope.newValue should change as it's an object reference, but $scope.newData is just a string value and is the same as stated above, it won't change. So, you always need to access it via $scope.newValue.data.
From console
newValue: Object {data: " "}
newData:
newValue: Object {data: Array[6]}
$scope.newData won't update, because it has still just the reference to that string value.
In your service you define your string value " ", TrialInfo.data holds only a reference to that string value. With $scope.newData = $scope.newValue.data; you copy that reference to $scope.newData. In your directive you copy the reference of the filereader to sharedTrialService.TrialInfo.data, but $scope.newData has still the reference to that string value. $scope.newData and TrialInfo.data hold different references.
$scope.newValue holds a reference to the object TrialInfo. You can do everything with its properties, but the reference to that object remains unchanged. So, if the data property changed you can still access it via $scope.newValue.data.
Maybe I'm not the best to explain it.

Bind javascript method in Angularjs template

My application is using Angularjs at client side. I have five directive which are using same logic. Following are required details of my code
I have one pure javascript class as AppUtilities.js having following method defined
var AppUtilities = {
//Get the guid for given collection
getGUID: function (collectionName) {
var prefix;
var guid;
//get first two character
if (!Utilities.isEmpty(collectionName)) {
prefix = collectionName.substring(0, 2);
//Get timestamp
var timestamp = Utilities.getTimestampId();
//concate prefix to get the guid
guid = prefix + timestamp;
}
return guid;
}
};
I have five different directive in which I need to use "getGUID()" method to bind with template. Since template is only able to bind with scope function therefore I have defined scope method in all these five template as below
scope.getGUID = function (collectionName) {
return AppUtilities.getGUID(collectionName);
}
Then in all the five directive template, this method is bind as scope variable
<h4 class="guid" id="guid" data-ng-bind-template="{{getGUID('goal')}}"></h4>
How can I avoid declaring these method as scope variable and directly use as AppUtilities.getGUID(collectionName) in the HTML template?
There are multiple ways, but honestly, it seems like more effort than its worth, since you can just do:
scope.getGUID = AppUtilities.getGUID;
Of course, you could use $rootScope, but to me personally it feels wrong - I like when things are explicitly declared and do not magically appear.
Alternatively, if you only need to render the GUID in the UI, create a GUID directive. For example:
.directive("guid", function(){
return {
template: "<span>{{getGUID()}}</span>",
link: function(scope, element, attrs){
scope.getGUID = function(){
return AppUtilities.getGUID(attrs.guid || attrs.name);
};
}
}
});
and use as:
<h4 class="guid"><guid name="goal"></guid></h4>
Without manipulating the individual scopes or the root scope, you could simply define a filter which is usable in all templates. Note that, for all the good reasons, I'd still define and inject AppUtilities, even if it is a global, as it's own service.
app.filter('toGUID', ['AppUtilities', function (AppUtilities) {
return function (input) {
return AppUtilities.getGUID(input);
};
}]);
// <pre>{{ 'goal'|toGUID }}</pre>
app.service('AppUtilities', function () {
return AppUtilities;
});
(function (app, ng) {
'use strict';
app.filter('toGUID', ['AppUtilities', function (AppUtilities) {
return function (input) {
return AppUtilities.getGUID(input);
};
}]);
app.service('AppUtilities', function () {
return AppUtilities;
});
var Utilities = {
isEmpty: function (collectionName) {
return false;
},
getTimestampId: function () {
return '_something';
}
};
var AppUtilities = {
//Get the guid for given collection
getGUID: function (collectionName) {
var prefix;
var guid;
//get first two character
if (!Utilities.isEmpty(collectionName)) {
prefix = collectionName.substring(0, 2);
//Get timestamp
var timestamp = Utilities.getTimestampId();
//concat prefix to get the guid
guid = prefix + timestamp;
}
return guid;
}
};
})(angular.module('app', []), angular);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0-rc.2/angular.min.js"></script>
<div data-ng-app="app">
<pre>{{ 'goal'|toGUID }}</pre>
</div>
Hide it in a div:
<div id="hidden" data-ng-model="hidden" style="display:none"></div>
<script>
$('#hidden').html(AppUtilities.getGUID(collectionName));
</script>
Then, ng-bind to the div's contents:
<div id="realDiv" data-ng-bind-html="hidden"></div>

Resources