AngularJS Bind to Service variables vs service functions? [closed] - angularjs

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
As an angularJS newbie, I am puzzled by the fact I have to bind to a function returned from the service to update the view, not the data itself, I couldn't find any official document explaining this, Does anyone know why?
JSFiddle Code Sample
<div ng-controller="MyCtrl">
binding to a function works!
<p ng-bind-html-unsafe="tempLog.returnBuffer()"></p>
<br><br>
bind to the service variable: Doesn't work, why?
<p>log={{tempLog.buffer}}</p>
<br><br>
bind to scope var instead of service var, still doesn't work
<p>log={{logBuffer}}</p>
bind to a scope var which points to the service Function, works!
<p>log={{pLogFunc()}}</p>
<button ng-click="addText('more')">Trace</button><br>
</div>
JS code
var myApp = angular.module('myApp',[]);
myApp.factory('myLog', function() {
var internalBuffer = "";
return {
buffer:internalBuffer,
trace:function(input){
internalBuffer = internalBuffer + "<br>" +input;
buff = input;
},
returnBuffer:function(){
return internalBuffer;
}
}
});
function MyCtrl($scope, myLog){
$scope.tempLog = myLog;
$scope.logBuffer = myLog.buffer;
$scope.pLogFunc = myLog.returnBuffer;
myLog.trace("aaa");
$scope.addText = function(str){
myLog.trace(str)
}
}

This is not an AngularJS binding problem, this is just how javascript works.
In your service:
1 buffer is assigned to a primitive variable internalBuffer.
2 trace() accepts a parameter that changes the internalBuffer primitive
3 returnBuffer() returns the internalBuffer primitive
Since trace() changes the internalBuffer primitive, any binding to buffer does not affect the changes in the internalBuffer, furthermore, returnBuffer() returns the value of the internalBuffer so naturally the changes you made with the trace() function affects the return value of the returnBuffer() function.
Any of these suggestions may work on your end:
[1] If you want to bind from the buffer property of your myLog service, then change your trace() function to something like this:
trace:function(input){
this.buffer = this.buffer + "<br>" +input;
}
[2] You may disregard the buffer property and solely use the returnBuffer() if youdon't want to expose yourinternalBufferand only use thetrace()to have access in changing theinternalBuffer`
[3] You can use both, the buffer property provides access to another buffer format while the internalBuffer holds all the private buffers / format / or anything else that you may not want to expose to the users of the service. Just be sure to update the buffer in your trace() function by using this as well.

Related

What is the significance of using functions when getting or setting data in angularjs service? [duplicate]

This question already has answers here:
Why use getters and setters/accessors?
(37 answers)
Closed 3 years ago.
I'm learning how to store API call response data in an AngularJS service. In all the examples that I saw, people used functions in the service to get or set values.
app.factory('dataFactory', function() {
let dataFactory = {};
let info;
dataFactory.setInfo = function(value){
info = value;
}
dataFactory.getInfo = function(){
return info;
}
return dataFactory;
});
But I realized that I could get and set values of variables in a service without the use of any functions.
app.factory('dataFactory', function() {
let dataFactory = {};
let dataFactory.info;
});
// Now I can get or set the value of this in my controller
app.controller('myCtrl', [dataFactory, function(dataFactory) {
dataFactory.info = "Value"; // setting the value
let test = dataFactory.info; // getting the value
}])
I would like to know if my approach could potentially lead to any problems. Is it considered a bad practice and if so why?
Preference to data accessors (getters and setters) over exposing a property directly is neither specific to AngularJS nor to JavaScript. Is generally a common practice in the object oriented programming.
One of the main reasons to prefer getters and setters over the direct access to a property is data encapsulation. When the data is defined as a local variable in the lexical environment of the service function (let info;) it is not possible to access it from outside (for example from controller).
Data accessors also give you a flexibility to add data access logic. For example you may want to implement some checks when the getter is called and make a decisions whether to return the data or not. Likewise, in the setter you may verify that the data (the setter was called with) meets the requirements and throw an error if it's not.
Further you may want to check this answer to see many other benefits getters and setters may provide.

$scope.$on fired 3 times [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I have 2 different angular controllers and one of it having broadcast like this
$timeout(function() {
if($scope.modal){
$rootScope.$broadcast(DATAINPUT_EVENT.REFRESH_COMPLETED_DATA_LIST,id);
$scope.modal.hide();
$scope.modal.remove();
}
}, 3000);
And in another controller I am catching broadcast.
$scope.$on(DATAINPUT_EVENT.REFRESH_COMPLETED_DATA_LIST,function(event,id){
// some action
});
Problem is $scope.$on function getting called 3 times. I have referred
AngularJs broadcast repeating execution too many times and
Angular - broadcast , $on called multiple times in directive
but could not get solution using them. Please help me out...!!
Quick and dirty hack: use a boolean flag
var once = true;
$timeout(function() {
if($scope.modal){
$rootScope.$broadcast(DATAINPUT_EVENT.REFRESH_COMPLETED_DATA_LIST, {id: id, once: once});
$scope.modal.hide();
$scope.modal.remove();
once = false;
}
}, 3000);
and in your listener:
$scope.$on(DATAINPUT_EVENT.REFRESH_COMPLETED_DATA_LIST,function(event,args){
if(args.once)
// some action, only the first time
});
Bear in mind this is (dirty, but still) solution only if you can't find why your broadcast it's called 3 times every event.
To fix issue for a moment, I did something like follows,
if(!$rootScope.$$listenerCount[DATAINPUT_EVENT.REFRESH_COMPLETED_DATA_LIST]){
$scope.$on(DATAINPUT_EVENT.REFRESH_COMPLETED_DATA_LIST,function(event,id){
// some action
});
}
But very soon I found I have initialized my controller multiple times and I have taken corrective actions to remove the multiple declarations of controller.

Ecommerce website not taking custom variables {{ }} [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm watching this video tutorial on building an e-commerce site with Angular and Moltin. I've gotten to the 19 minute mark where he begins creating the product.html view.
I'm not sure why, but I can console.log(product) just fine, but when I try to use variables like {{ product.title} in my product.html view, it doesn't show. Plain text shows up fine, and in my category.html view I can get my categories to ng-repeat using {{ category.title }} just fine.
I am not sure why I can log the product object, but the view will not render it.
Here's a link to my GitHub repo. Any help is appreciated.
There is a scope conflict being caused because you are declaring product to be your controller with the controllerAs statement here, and then setting $scope.product in your controller here
You need to resolve this conflict by either renaming $scope.product to something else in the controller, or renaming your controllerAs: 'product' statement.
I was able to make this work by changing controllerAs:'product' to controllerAs:'prod', but any solution resolving the conflict between the variable names should work.
Could you provide any snippets or a fiddle of when you initialize products? Just from glancing at the video it seems that the promise from your ProductCtrl might not be fulfilled by the time you are invoking the console.log(); What value are you getting when you console.log()?
Also, although this doesn't seem to be the issue- I have seen the same issue when binding to primitive types!
A simple check could be trying to instantiate the product to an empty object: $scope.product = {}; somewhere in the same context BEFORE you are setting to new value- that way angular's magic will know to watch and bind that object in the digest cycle.

Best practices for $resources bound directly on scope [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
In angular when using resources we can bind them directly on the $scope like this:
$scope.users = Users.$query();
This could also written as:
Users.$query().$promise.then(function(users) {
$scope.users = users;
});
Have you experienced any downside of using the first approach? What are the pros and cons of each?
From angular ng-book:
$resource Instances Are Asynchronous
With all these methods, it’s important to note that when they are
invoked, the $resource object immediately returns an empty reference
to the data. This data is an empty reference, not the actual data, as
all these methods are executed asynchronously. Therefore, a call to
get an instance might look synchronous, but is actually not. In fact,
it’s simply a reference to data that Angular will fill in
automatically when it arrives back from the server.
// $scope.users will be empty
$scope.users = User.query();
We can wait for the data to come back as expected using the callback method that the methods
provide:
$scope.users(function(users) {
// logic here
});
or use raw $http from $promise attribute
$scope.users.$promise.then(function(users) {
// logic here
});
Both approaches are essentially equivalent.
The main difference between them is that in the 2nd approach, you will be able to perform certain actions once the request completes, whereas in the 1st approach, to be able to run logic when the request completes, you'll need to work with $watch statements on the users variable.
The 1st approach however, will allow you to place default values inside user which could be convenient when binding view before the request completes.
By the way, there is also a 3rd option:
$scope.users = Users.$query();
$scope.users.$promise.then(function(users) {
// perform some logic
});
This allows you to immediately bind views to the users variable in the scope, and at the same time, perform any additional logic you might need once the request completes.

AngularJS: append partial instead of replacing current view

I wondered if it's possible to append a partial to the view, instead of replacing the previous one.
The usecase is as follows:
I'm building a questionaire
Upon starting the questionaire only 1 question is visible/in the DOM
The answer of question 1 dictates what question 2 should be
Upon answering question 1, question 2 gets appended to the DOM, under question 1
If question 1 is changed, all other questions are reset/removed from dom, and a fresh, unanswered question 2 appears (under 1)
Maybe using one partial a question is not the way to go, in that case please let me know what the preferred method would be (vanilla/no-angular JS?)
To give you a rough idea:
Given your app is in angularjs, you should be having all your questions inside a model in a controller:
$scope.questions = [
{
"question":"foo?",
"options":["bar1","bar2","bar3","bar4"]
"answer":2
},
{
},
{
}
];
// initially show the 1st question
$scope.currentQuestIndex = 0;
$scope.currentQuestion = $scope.questions[$scope.currentQuestIndex];
And use the currentQuestion inside your view as:
<div>Question: {{currentQuestion.question}}</div>
When the user selects a correct answer, you could simply update the current question:
$scope.submitAnswer = function(){
// check if the answer is correct
if(isCorrect){
$scope.currentQuestion = $scope.questions[$scope.currentQuestIndex + 1];
}
}
This would dynamically update your view! Thanks to the data-binding feature provided by angularjs.

Resources