Issues with calling function from template - javascript

In one case I have a problem with running a function on the Controller from the template. The value becomes a string containing the function signature, not the value that should be returned from the function.
When I use {{ getSomeObject(d) }} in my template markup it works fine, and it prints the object values, meaning that the function got called on the Controller.
I have tried with and without the {{ }}.
Pseudo code:
<div class"xyz" data-lav-fact="getSomeObject(d)"> <!-- Does not work here -->
{{ getSomeObject(d) }} <!-- Works here -->
</div>
And of course the function is added to the scope in the Controller:
$scope.getSomeObject = function(data) {
return { key: "test" };
};
This works in other parts of the application and I don't know what wrong in this case.
Does anyone know what typically can be wrong here?

Since you are trying to set an attribute with a $scope function, you'll need to {{ interpolate }} and use ngAttr attribute bindings. Here is a simple example that shows this in action. Examine the difference between the elements logged out. As you dig, you'll see your { key: 'test' } value being set
<div id="without" data-lav-fact="getSomeObject()">without</div>
<div id="with" ng-attr-data-lav-fact="{{ getSomeObject() }}">with</div>
app.controller('ctrl', ['$scope', function($scope) {
$scope.getSomeObject = function() {
return { key: 'test' };
}
var w = angular.element(document.getElementById('with'));
var wo = angular.element(document.getElementById('without'));
console.log(w[0].attributes); // has value
console.log(wo[0].attributes); // does not have value
}]);
JSFiddle Link

Related

Unable to set the value of bound property in angular component

I'm trying to implement a bound property for an angular component as explained in the component documentation and this example.
Unfortunately the values I'm assigning at the tag level or in the $onInit methods are never used. Nor is the value printed when I use it as a model value.
You can find the full code on plunker.
My binding definition:
(function(angular) {
'use strict';
function SearchResultController($scope, $element, $attrs) {
var ctrl = this;
ctrl.searchFor = 'nohting-ctor';
ctrl.$onInit = function() {
console.log('SearchResultController.$onInit: searchFor='+ctrl.searchFor);
ctrl.searchFor = 'nothing-int';
};
}
angular.module('myApp').component('searchResult', {
templateUrl: 'searchResult.html',
controller: SearchResultController,
bindings: {
searchFor: '<'
}
});
})(window.angular);
Template:
<p>SearchResult for <span ng-model="$ctrl.searchFor"</span></span></p>
How it's used:
<h1>Main Window</h1>
<search-input on-start-search="$ctrl.startSearch(value)"></search-input>
<search-result search-for="nothing-ext"></search-result>
None of the nothing-* values is evers shown.
Any ideas what's wrong?
The usage of you component is not correct. If you want to pass a string it should be quoted:
<search-result search-for="'nothing-ext'"></search-result>
Then next problem is that this line
<p>SearchResult for <span ng-model="$ctrl.searchFor"</span></span></p>
doesn't make sense, as ngModel directive is only valid for input controls. You want ngBind or simple {{ $ctrl.searchFor }}:
<p>SearchResult for <span ng-bind="$ctrl.searchFor"</span></span></p>

Angulrjs: A controller doesn't send a value via a factory with the "as" statement

I've been teaching myself how to use the as statement of Angularjs's controller, but struggling to make controllers communicate with others, using the as syntax.
<script type="text/javascript">
angular.module('angularApp', [])
.factory('MessageService', function(){
var message = {
addedItem: "initialMessge"
};
return {
returnMessage: message//This is supposed to be the "var message" defined above
};
})
.controller('DiaplayingProductController', function(MessageService){
var instance = this;
this.data = {
message: MessageService.returnMessage.addedItem
};
})
.controller('ProductController', function($scope, $http, MessageService) {
var instance = this;
this.data = {
message: MessageService.message,
//There are other stuff here
};
this.addItem = function(productName) {
$http({
//other tasks
}).then(function addSucces(response) {
instance.data.message.addedItem = productName;
});
};
});
<span ng-controller="DiaplayingProductController as dpc" ng-bind="dpc.data.message"></span>
<div ng-controller="ProductController as pc">
#foreach ($products as $index => $product)
<div class="product">
<button ng-click="pc.addItem({{$product->name}})>
Add it to Cart
</button>
</div>
#endforeach
</div>
I use Laravel, so {{$product->name}} and #foreach are Laravel's expression.
In a nutshell,
There are one <span> and multiple <button>s, based on the result of #foreach (Again, I use Laravel, so this is basically the same thing as php's foreach)
When one of the <button> is pressed, the content of <span> is supposed to be updated.
The event is triggered in ProductController, which is supposed to update message of DiaplayingProductController, via MessageService.
The message is not going to be sent to the span tag.
This question may be silly. However, there are not many information resources out there which deal with this as statements, so I'd like to ask some advice here. Thank you in advance!
What's this #foreach?
There's a coma in your attributes. Shouldn't be there.
The expression in your ng-click has a missing parenthesis. Also, it should be an expression, therefore the {{}} have nothing to do here.
The data object are not shared between the controllers. You should:
use directives and pass the data using attributes ('=').
set the data in the $scope, which is not as good a solution
use a service as an intermediary (each controller can set/get the value
from that service)

Expression in data attribute for angular chart.js

Hi I have tried using an expression inside the data attribute like this
<div ng-repeat="item in items">
<canvas data="getTheData(item.value)"></canvas>
</div>
and in the controller
var getData = {
first: function(){ return angularFactory.getData() };
second: function(){ return angularFactory.getData() };
}
$scope.getTheData = function(value){
getData[value]().then(function(data){
console.log(data);
});
};
my plan is to get only the needed data from factories based on what items the user load.
the problem is this is resulting in [$rootScope:infdig] with a log that never stops even though I just have one item in the "item" list.
Am I doing this wrong?
You could have something like this, I'm not sure this will work or not
Call an getTheData on rendering of DOM, you should pass item inside that method instead of item.value
<div ng-repeat="item in items" ng-init="getTheData(item)">
<canvas data="item.data"></canvas>
</div>
Code
$scope.getTheData = function(item){
getData[item.value]().then(function(data){
item.data = data;
console.log(data);
});
};
So inside the success of getData function you need to set item.data value that will get passed to canvas data attribute.

Saving an item through factory casts an error with AngularJS and Firebase

I'm using Firebase and AngularJS bundled up together and as I'm in the learningprocess of both, I guess. I'm having some trouble saving an item through a factory with Angular.
This is my script
var app = angular.module('LinkApp', ['firebase']);
app.constant('FirebaseLinks', 'https://[hidden].firebaseio.com/links')
app.controller('LinkCtrl', ['$scope', 'LinksFactory',
function($scope, LinksFactory) {
// get links
$scope.links = LinksFactory.getItems();
// update link
$scope.updateLink = function(link) {
LinksFactory.updateItem(link);
};
}
]);
app.factory('LinksFactory', ['$firebase', 'FirebaseLinks',
function($firebase, FirebaseLinks) {
var ref = new Firebase(FirebaseLinks);
var items = $firebase(ref);
return {
getItems: function() {
return items.$asArray();
},
updateItem: function(item) {
items.$save(item);
}
};
}
]);
This is my html
<div ng-repeat="link in links | orderBy: link.number">
<input type="number" ng-model="link.number" ng-blur="updateLink(link)">
{{ link.name }}: {{ link.url }}
</div>
I'm using my blur function (updateLink) to pass my item into my factory, but from there I get this error: "TypeError: undefined is not a function".
If I pass my item to my function and save my collection from there width $scope.links.$save(link), it is successfull.
How can this be?
Thanks in regards. Say if you need further details.
After a lot of work I figured it out.
I had to return my factory functions and I had to call my variable 'items' with an $asArray() at the end and remove the $asArray() from my getItems function.
But now it works :)

$digest rendering ng-repeat as a comment

I'm writing a test for a directive, when executing the test the template (which is loaded correctly) is rendered just as <!-- ng-repeat="foo in bar" -->
For starters the relevant parts of the code:
Test
...
beforeEach(inject(function ($compile, $rootScope, $templateCache) {
var scope = $rootScope;
scope.prop = [ 'element0', 'element1', 'element2' ];
// Template loading, in the real code this is done with html2js, in this example
// I'm gonna load just a string (already checked the problem persists)
var template = '<strong ng-repeat="foo in bar"> <p> {{ foo }} </p> </strong>';
$templateCache.put('/path/to/template', [200, template, {}]);
el = angular.element('<directive-name bar="prop"> </directive-name>');
$compile(el)(scope);
scope.$digest(); // <--- here is the problem
isolateScope = el.isolateScope();
// Here I obtain just the ng-repeat text as a comment
console.log(el); // <--- ng-repeat="foo in bar" -->
}));
...
Directive
The directive is fairly simple and it's not the problem (outside the test everything works just fine):
app.directive('directiveName', function () {
return {
restrict : 'E',
replace : true,
scope : {
bar : '='
},
templateUrl : '/path/to/template', // Not used in this question, but still...
});
A few more details:
The directive, outside the test, works fine
If I change the template to something far more simple like: <h3> {{ bar[0] }} </h3> the test works just fine
The rootScope is loaded correctly
The isolateScope results as undefined
If you have a look at the generated output that angular creates for ng-repeat you will find comments in your html. For example:
<!-- ngRepeat: foo in bars -->
These comments are created by the compile function - see the angular sources:
document.createComment(' ' + directiveName + ': '+templateAttrs[directiveName]+' ')
What you get if you call console.log(el); is that created comment. You may check this if you change the output in this way: console.log(el[0].parentNode). You will see that there are a lot of childNodes:
If you use the directive outside of a test you will not be aware of this problem, because your element directive-name will be replaced by the complete created DocumentFragment. Another way to solve the problem is using a wrapping element for your directive template:
<div><strong ng-repeat="foo in bar"> <p> {{ foo }} </p> </strong></div>
In this case you have access to the div element.

Categories

Resources