Pass a parameter into function called in template - angularjs

Here is my angular code:
'use strict';
var app=angular.module('app',['ngRoute','appFactories']);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/admin', {
templateUrl: '/pages/admin/allcards.html',
controller: 'MainController'
})}]);
var factories=angular.module('appFactories',['ngResource']);
factories
.factory('CardFactory',['$resource',
function($resource) {
return{
all: $resource('/worldonlinenew/card/common', {}, {query: {method: 'GET', params: {id: '#id'}}}),
}
}])
.factory('StaticFactory',['$resource',
function($resource) {
return{
languages: $resource('/worldonlinenew/static/languages', {}, {query: {method: 'GET',isArray: true}}),
}
}]);
app.controller('CardController',function CardController($scope, CardFactory, StaticFactory){
$scope.card=null;
$scope.languages=null;
$scope.translate=function(language, text){
for(var i=0;i<text.translatedTexts.length;i++){
if(text.translatedTexts[i].language==language){
return translate;
}
}
}
$scope.initCard = function(id){
$scope.card=CardFactory.all.query({id: id});
$scope.languages=StaticFactory.languages.query({id: id});
}
});
And here is my template, where i'm trying to call this function:
</head>
<body ng-controller="CardController" >
<div class="container">
<div th:attr="ng-init='initCard(\''+${id}+'\');'"></div>
<h4 sec:authentication="name"></h4>
<div class="row-fluid">
<h1>Card ID: {{card.id}}</h1>
<!-- Next two strings works fine -->
<h1>name one: {{card.name.translatedTexts[0].content}}</h1>
<h1>name two: {{card.name.translatedTexts[1].content}}</h1>
<div ng-repeat="language in languages" ng->
<h1 ng-bind="translate(language,card.name)"></h1>
</div>
</div>
</div>
</body>
</html>
My browser's console print something like "can't get translatedTexts of undifined, i.e. text parameter is undifined. But language parameter is ok, because it's declared in ng-repeat.

Ok, working sample code here. If card.name always undefined it means when iterator working but var not ready on not in same scope in same time. See sample and check your code.
[Update]
Yes. Problem in initCard function. This function 'sync' but $resource native async (CardFactory.all.query,StaticFactory.languages.query). And you must wait when function resolve.
Example:
app.controller('CardController',function($scope,CardFactory){
init();
/////////
function init(){
CardFactory.all.query({id:1})
.$promise
.then(function(result){
// ready
});
// or
CardFactory.all.query({id:1}, function(cards){
// ... if
$scope.cards = cards;
});
}
})
working code here
angular $resource docs

Finally, here is the answer! As i've wrote, ng-bind=translate(language,card.name) executes before init function, and as we can see, in my model $scope.card=null;. So, field card.name not only empty, this field doesn't exists.
Solution:
function Card(){
this.id=new Number();
this.name=new Text();
}
function Text(){
this.id=new Number();
this.name=new String();
this.translatedTexts=new Array();
}
$scope.card=new Card();

Related

Scoping issue - page not being updated from http post in sibling controller

I am using ng-click to call a function that request new content for the scope. Im doing that by calling a post request that is handeled by php.
When I run the script I can see the updated data in the console but the page is not being updated.
The HTML;
<body>
<div id ="error_frame" class="system hidden"> </div>
<div ng-controller="objectNavCtrl" id = "content">
<a ng-click="update()">link</a>
</div>
<div ng-controller="objectCtrl" >
<div id="object_container" ng-repeat="object in objects track by object.id">
<div>{{object.name}}</div>
</div>
</div>
</body>
The AngularJS app;
'use strict';
var angular_app = angular.module('angular_app', []);
angular_app.controller('objectCtrl', ['$scope','$http', function ($scope,$http) {
$http({
method: 'get',
url: 'ajax-processor.php'
}).then(function successCallback(response) {
$scope.objects = response.data;
});
}]);
angular_app.controller('objectNavCtrl', ['$scope','$http', function ($scope,$http) {
$scope.update = function(){
console.log('clicked');
$http({
method: 'post',
url: 'ajax-processor.php',
data: {'ajaxKey':'Mykey'}
}).then(function successCallback(response) {
$scope.objects = response.data;
console.log(response.data);
});
}
}]);
I use the get method when the page is loading and try to update it with the update function.
The problem is that two controllers are on separate scopes. Put the common data on the scope of a parent controller:
<body>
<!-- Common scope -->
<div ng-controller="parent as common">
<!-- Separate Scope -->
<div ng-controller="objectNavCtrl" id = "content">
<a ng-click="update()">link</a>
</div>
<!-- Separate Scope -->
<div ng-controller="objectCtrl" >
̶<̶d̶i̶v̶ ̶i̶d̶=̶"̶o̶b̶j̶e̶c̶t̶_̶c̶o̶n̶t̶a̶i̶n̶e̶r̶"̶ ̶n̶g̶-̶r̶e̶p̶e̶a̶t̶=̶"̶o̶b̶j̶e̶c̶t̶ ̶i̶n̶ ̶o̶b̶j̶e̶c̶t̶s̶ ̶t̶r̶a̶c̶k̶ ̶b̶y̶ ̶o̶b̶j̶e̶c̶t̶.̶i̶d̶"̶>̶
<!--use common scope here -->
<div id="object_container" ng-repeat="object in common.objects track by object.id">
<div>{{object.name}}</div>
</div>
</div>
</div>
</body>
angular_app.controller('objectNavCtrl', ['$scope','$http', function ($scope,$http) {
$scope.update = function(){
console.log('clicked');
$http({
method: 'post',
url: 'ajax-processor.php',
data: {'ajaxKey':'Mykey'}
}).then(function successCallback(response) {
̶$̶s̶c̶o̶p̶e̶.̶o̶b̶j̶e̶c̶t̶s̶ ̶=̶ ̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶;̶
$scope.common.objects = response.data;
console.log(response.data);
});
}
}]);
For more information, see
AngularJS Developer Guide - Scope Hierarchies
AngularJS Wiki - Understanding Scopes.
You are tracking the changes by id. So as long the object's ids don't change, the page won't be refreshed. Try to leave the track by out or for better performance, do it with some properties you compare or your own comparer function as described here: ng-repeat with track by over multiple properties

Angularjs: Cannot display array items using ng-repeat

I am using AngularJs to retrieve the data from ASP.Net Controller.
The Json data is retrieved from the server, but can't figure out why cannot display array items when using the ng-repeat:
var app = angular.module('Appp', []);
app.controller('metadataCtrl', function ($scope, $http) {
$scope.lookupItems = {};
$http({ method: 'GET', url: '/home/listvalues?listid=3' }).then(function (response) {
$scope.lookupItems = response;
console.log($scope.lookupItems);
},
function (error) { alert("error"); });
// console.log($scope.listItems);
});
<form name="myForm" ng-controller="metadataCtrl" class="my-form">
<div ng-repeat="item in lookupItems">
{{$index}}
{{item.ListValueID}}
</div>
</form>
The Json Retrieved from the server:
[{"ListValueID":13,"Translation":{"TranslationID":0,"Value":"Important","LanguageValues":{"ar":"مهم","en":"Important"}},"ListCategory":{"ListID":4,"Translation":{"TranslationID":0,"Value":"","LanguageValues":{"ar":"","en":""}}},"Parent":0},
{"ListValueID":14,"Translation":{"TranslationID":0,"Value":"Less Importance","LanguageValues":{"ar":"أقل أهمية","en":"Less Importance"}},"ListCategory":{"ListID":4,"Translation":{"TranslationID":0,"Value":"","LanguageValues":{"ar":"","en":""}}},"Parent":0},
{"ListValueID":15,"Translation":{"TranslationID":0,"Value":"Very Important","LanguageValues":{"ar":"كثير الأهمية","en":"Very Important"}},"ListCategory":{"ListID":4,"Translation":{"TranslationID":0,"Value":"","LanguageValues":{"ar":"","en":""}}},"Parent":0}]
The most likely issue (assuming that your app and controller are constructed and referenced properly) is that the object returned from the promise contains a .data property which actually holds your JSON data.
Try this:
$http({ method: 'GET', url: '/home/listvalues?listid=3' })
.then(function (response) {
$scope.lookupItems = response.data;
console.log($scope.lookupItems);
},
function (error) {
alert("error");
});
I think you just forgot to wrap your app with ng-app:
var app = angular.module('Appp', []);
app.controller('metadataCtrl', function ($scope, $http) {
$scope.lookupItems = {};
$scope.lookupItems = [{"ListValueID":13,"Translation":{"TranslationID":0,"Value":"Important","LanguageValues":{"ar":"مهم","en":"Important"}},"ListCategory":{"ListID":4,"Translation":{"TranslationID":0,"Value":"","LanguageValues":{"ar":"","en":""}}},"Parent":0},
{"ListValueID":14,"Translation":{"TranslationID":0,"Value":"Less Importance","LanguageValues":{"ar":"أقل أهمية","en":"Less Importance"}},"ListCategory":{"ListID":4,"Translation":{"TranslationID":0,"Value":"","LanguageValues":{"ar":"","en":""}}},"Parent":0},
{"ListValueID":15,"Translation":{"TranslationID":0,"Value":"Very Important","LanguageValues":{"ar":"كثير الأهمية","en":"Very Important"}},"ListCategory":{"ListID":4,"Translation":{"TranslationID":0,"Value":"","LanguageValues":{"ar":"","en":""}}},"Parent":0}];
console.log($scope.lookupItems);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="Appp">
<form name="myForm" ng-controller="metadataCtrl" class="my-form">
<div ng-repeat="item in lookupItems">
{{$index}}
{{item.ListValueID}}
</div>
</form>
</body>
You probably misspelled Appp. Make sure your module definition in your javascript:
var app = angular.module('App', []); //Changed to App from Appp
matches your app declaration in your html
<div ng-app="App">
...controller declaration...
...body.....
</div>

How should you access controller functions from other modules

I am having a hard time understanding how Modules should interact with each other in Angularjs. I would like to break the application into nice small modules, but I cannot seem to find the correct way to have these modules interact with each other.
JSFiddle:
http://jsfiddle.net/jwest80/o5o3sr8q/4/
The code shows a breadcrumb I would like to have at the top of the page. The BreadCrumb is in its own module 'bread' and included inside a parent module 'ngFSCH'.
There is a list outside BreadCrumb controller section whose actions should add breadcrumbs. However, I do not understand the correct way to access this addCrumb function. I can only make it work if it is called from inside the breadcrumb controller section in the markup.
Markup:
<div ng-app="ngFSCH">
<section ng-controller="BreadCrumbsCtrl">
<span ng-repeat="crumb in crumbs" class="breadcrumbs">
<span ng-hide="isLast($index)" ng-click="selectCrumb($index)">{{crumb.text}} > </span>
<span ng-show="isLast($index)">{{crumb.text}}</span>
</span>
</section>
<section>
<h4>Add Some Crumbs</h4>
<ul>
<li>Company</li>
<li>Department</li>
<li>User</li>
</ul>
</section>
</div>
Script:
var ngFSCH = angular.module('ngFSCH', ['bread']);
(function () {
var app = angular.module('bread', []);
app.controller('BreadCrumbsCtrl', ['$scope', '$log', function ($scope, $log) {
$scope.crumbs = [{ text: "Crumb 1", url: "url1" }, { text: "Crumb 2", url: "url2" }];
$scope.isLast = function(index) {
return index === $scope.crumbs.length-1;
}
$scope.addCrumb = function (newCrumb) {
$scope.crumbs.push({ text: newCrumb, url: "TestURL" });
}
$scope.selectCrumb = function (index) {
$log.info($scope.crumbs[index].url);
$scope.crumbs = $scope.crumbs.slice(0, index + 1);
}
}]);
})();
I would encapsulate the bread crumb functionality in a service and create a controller for the section with the links (that add the breadcrumbs). The new controller can then use the service to add and remove crumbs from the array. You can also add the crumbs array into a value.. Your controllers can then expose the add and select features to the tiny portions of html they control without polluting other sections of your page.
Here is the result. Hope it helps!
JSFiddle
Here is the code:
var app = angular.module('bread', []);
app.value('crumbs', [
{ text: "Crumb 1", url: "url1" },
{ text: "Crumb 2", url: "url2" }
]);
app.factory("BreadCrumbsService", ['$log', 'crumbs', function ($log, crumbs) {
var service = {
getCrumbs: getCrumbs,
addCrumb: addCrumb,
selectCrumb: selectCrumb
};
return service;
//I did not add a set crumbs because you can set it directly.
function getCrumbs(){
return crumbs;
}
function addCrumb(newCrumb) {
crumbs.push({
text: newCrumb,
url: "TestURL"
});
}
function selectCrumb(index) {
$log.info(crumbs[index].url);
crumbs = crumbs.slice(0, index + 1);
}
}]);
app.controller('BreadCrumbsCtrl', ['$scope', 'BreadCrumbsService', function ($scope, BreadCrumbsService){
$scope.crumbs = BreadCrumbsService.getCrumbs;
$scope.selectCrumb = BreadCrumbsService.selectCrumb;
$scope.isLast = function (index) {
return index === BreadCrumbsService.getCrumbs().length - 1;
}
}]);
app.controller('AddLinksCtrl', ['$scope', 'BreadCrumbsService', function ($scope, BreadCrumbsService) {
$scope.addCrumb = BreadCrumbsService.addCrumb;
}]);
Here is the links section with the new controller:
<section ng-controller="AddLinksCtrl">
<h4>Add Some Crumbs</h4>
<ul>
<li>Company</li>
<li>Department</li>
<li>User</li>
</ul>
</section>
That is intended because you are working within the scope of the controller. How about moving the ng-controller directive to the containing div where ng-app is?
<div ng-app="ngFSCH" ng-controller="BreadCrumbsCtrl">

AngularJS: how to modify an array in the service from multiple controllers

I want to have an array in the service, which can be modified from different controllers.
The purpose of this is the have an array accessible through every controller.
I want to be able to push items to this array from controllers, as well to delete them.
Service:
.service('EmailOps', function () {
var templates = [];
return {
pushToEmailBody: function (newObj) {
templates.push(newObj);
console.log(templates);
}
};
});
Controller:
angular.module('app')
.controller('mainCtrl', function ($scope, $rootScope, EmailOps) {
$scope.include = EmailOps.pushToEmailBody;
});
HTML:
<div ng-controller="mainCtrl">
1
2
3
</div>
To summarize, I would like to be able to add multiple new elements to the array in the service by clicking on these links. Currently when it adds one of them, it replaces the one added before, so that I have an array with one element only. Any idea what I might be doing wrong?
please see here : http://jsbin.com/gesirira/1/edit
service:
app.service('EmailOps', function () {
var templates = [];
function pushToEmailBody (newObj) {
templates.push(newObj);
console.log(templates);
}
return {
templates:templates,
pushToEmailBody : pushToEmailBody
};
});
controller:
app.controller('firstCtrl', function($scope,EmailOps){
$scope.include = function(obj)
{
EmailOps.pushToEmailBody(obj);
};
$scope.temp = EmailOps.templates;
});
html:
<body ng-app="app">
<div ng-controller="firstCtrl">
1
2
3
<br/>
templates: {{temp |json}}
</div>
</div>
</body>
You can modify your service like this
.service('EmailOps', function () {
this.templates = [];
this.pushToEmailBody = function (newObj) {
templates.push(newObj);
console.log(templates);
}
});
and then in the controller :
$scope.include = function(obj)
{
EmailOps.pushToEmailBody(obj);
};

Working with two modules in AngularJS

I have two modules with different operations and I tried to work with them as shown below.
<div id="viewBodyDiv" ng-app="xhr">
<div ng-controller="xhrCtrl">
<button ng-click="callAction()">Click</button>
{{sample}}
</div>
</div>
<div id="viewBodyDiv2" ng-app="xhr2">
<div ng-controller="xhr2Ctrl">
<button ng-click="alertMessage()">Click</button>
</div>
</div>
The JS is shown below.
angular.module('xhr', []).controller('xhrCtrl', function ($http, $scope, $window) {
$scope.sample = "sadf";
$scope.callAction = function () {
$http({
method: 'GET',
url: 'Angular/GetData',
params: {
api_key: 'abc'
}
}).then(function (obj) { //I get a text result that I display near the button
$scope.sample = obj.data;
});
};
});
angular.module('xhr2', []).controller('xhr2Ctrl', ['$window','$scope',
function ($window,$scope) {
$scope.alertMessage = function () {
$window.alert("xhr2Ctrl clicked");
};
}]);
When I click on the viewBodyDiv I am getting the desired output but when I click on viewBodyDiv2 the alert message is not getting displayed.
I am new to AngularJS and please let me know what I am doing wrong or what it the procedure to work with two different Modules in Angular.
Thank you.
add this code to the bottom of your JavaScript
angular.element(document).ready(function() {
angular.bootstrap(document.getElementById('viewBodyDiv2'),['xhr2']);
});
Hope this helps.
As per the AngularJS documentation:
https://docs.angularjs.org/api/ng/directive/ngApp
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application.
However, if you still want to do it this way, you have to use angular.boostrap() manually to achieve this. Here is a good tutorial on this:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
So you need to bootstrap the module to have multiple angular apps on the same page.
You can also inject one of the modules into another.
var xhrModule = angular.module("xhr", ["xhr2"]);
Following is a sample code for bootstrapping the module.
<html>
<head>
<script src="angular.min.js"></script>
</head>
<body>
<div id="viewBodyDiv" ng-app="xhr">
<div ng-controller="xhrCtrl">
<button ng-click="callAction()">Click</button>
{{sample}}
</div>
</div>
<div id="viewBodyDiv2" ng-app="xhr2">
<div ng-controller="xhr2Ctrl">
<button ng-click="alertMessage()">Click</button>
</div>
</div>
<script>
var xhrModule = angular.module("xhr", []);
xhrModule.controller('xhrCtrl', function ($http, $scope, $window) {
$scope.sample = "sadf";
$scope.callAction = function () {
$http({
method: 'GET',
url: 'Angular/GetData',
params: {
api_key: 'abc'
}
}).then(function (obj) { //I get a text result that I display near the button
$scope.sample = obj.data;
});
};
});
var xhr2Module = angular.module("xhr2", [])
xhr2Module.controller('xhr2Ctrl', ['$window','$scope',
function ($window,$scope) {
$scope.alertMessage = function () {
$window.alert("xhr2Ctrl clicked");
};
}]);
angular.bootstrap(document.getElementById("viewBodyDiv2"),['xhr2']);
</script>

Resources