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

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

Related

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>

Where to persist data used by many controllers in AngularJS? [duplicate]

I'm new to angular and I'm wondering how I can share a variable between controllers in angular. I'm using the following scripts -
In Main.js:
function MainCntl($scope) {
---code
}
function SearchCtrl($scope, $http) {
$scope.url = 'http://10.0.0.13:9000/processAdHoc';
$scope.errorM = "No results";
$scope.search = function() {
$http.post($scope.url, { "data" : $scope.keywords}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
$scope.result = data;
alert('yes');
})
.
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
alert('no');
$scope.result = "failed";
});
};
}
In Index.html
<body ng-controller="MainCntl" >
---code
<div ng-controller="SearchCtrl">
<form class="well form-search">
<div class="ui-widget">
<label for="tags"></label>
<a ng-click="search()"><input type="image" src="../../images/search1.png" class="searchbox_submit" /></a>
<input ng-model="keywords" placeholder="Shadow Search" id="tags" class="input-medium search-query rounded" />
</div>
</form>
</div>
---code
<p ng-model="result">
{{result}}
</p>
</body>
Everything works well with the ajax I'm sending data and receiving a response, my question is as follows:
In the SearchCtrl function I have a variable called $scope.result that is later referred to in Index.html. If I insert the html code that contains that variable into the SearchCtrl controller it works fine but if it is in the MainCtrl controller it does not work. How can I share this variable between the controllers.
Thanks ahead
Use a service and inject it to both controllers and refer your scope vars to the services variable.
Example:
angular.module("yourAppName", []).factory("myService", function(){
return {sharedObject: {data: null } }
});
function MainCtrl($scope, myService) {
$scope.myVar = myService.sharedObject;
}
function SearchCtrl($scope, $http, myService) {
$scope.myVar = myService.sharedObject;
}
In your template do:
{{myVar.data}}
See an example Uses Angular v1.1.5
The reason you put it in an inner object is to preserve your references, if you keep it without a "sharedObject", and change that object, your binding will be pointing to the old reference and wouldn't show anything in the template.

What to use instead of $rootScope? [duplicate]

I'm new to angular and I'm wondering how I can share a variable between controllers in angular. I'm using the following scripts -
In Main.js:
function MainCntl($scope) {
---code
}
function SearchCtrl($scope, $http) {
$scope.url = 'http://10.0.0.13:9000/processAdHoc';
$scope.errorM = "No results";
$scope.search = function() {
$http.post($scope.url, { "data" : $scope.keywords}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
$scope.result = data;
alert('yes');
})
.
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
alert('no');
$scope.result = "failed";
});
};
}
In Index.html
<body ng-controller="MainCntl" >
---code
<div ng-controller="SearchCtrl">
<form class="well form-search">
<div class="ui-widget">
<label for="tags"></label>
<a ng-click="search()"><input type="image" src="../../images/search1.png" class="searchbox_submit" /></a>
<input ng-model="keywords" placeholder="Shadow Search" id="tags" class="input-medium search-query rounded" />
</div>
</form>
</div>
---code
<p ng-model="result">
{{result}}
</p>
</body>
Everything works well with the ajax I'm sending data and receiving a response, my question is as follows:
In the SearchCtrl function I have a variable called $scope.result that is later referred to in Index.html. If I insert the html code that contains that variable into the SearchCtrl controller it works fine but if it is in the MainCtrl controller it does not work. How can I share this variable between the controllers.
Thanks ahead
Use a service and inject it to both controllers and refer your scope vars to the services variable.
Example:
angular.module("yourAppName", []).factory("myService", function(){
return {sharedObject: {data: null } }
});
function MainCtrl($scope, myService) {
$scope.myVar = myService.sharedObject;
}
function SearchCtrl($scope, $http, myService) {
$scope.myVar = myService.sharedObject;
}
In your template do:
{{myVar.data}}
See an example Uses Angular v1.1.5
The reason you put it in an inner object is to preserve your references, if you keep it without a "sharedObject", and change that object, your binding will be pointing to the old reference and wouldn't show anything in the template.

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>

How do I get angularjs routes to display partials in IE 7 and 8?

I'm using AngularJS in a project and am trying to use the included routing for navigation.
I'm having a problem in IE7 and 8. When I go to one of the pages, the controller fires and the data loads. (I can see the partial being returned with all the data bound fields populated.) The problem is that the partial doesn't get added/appended to the ng-view. I started out using AngularJS v1.0.1 but now switched to 1.0.2 thinking that perhaps it was a bug in the version I was using. Any help would be greatly appreciated.
This is the code that I'm using for routing:
myApp.config(['$routeProvider', function($routeProvider, $location){
$routeProvider.when('/business/:query', { templateUrl: 'partials/detail.html', controller: 'details'});
$routeProvider.when('', { templateUrl: 'partials/splash.html'});
$routeProvider.when('/results/:query', { templateUrl: 'partials/list.html', controller: 'listController'});
$routeProvider.otherwise({redirectTo: ''});
}]);
This is the code for the controller:
myApp.controller('listController', listController = function($scope, $routeParams, $http, $cookies){
var query = $routeParams.query;
var myQuery = query.indexOf('-') > 0 ? $scope.removeDashes(query):query;
switch($scope.selected)
{
case 'name':
$http({ method: 'jsonp',
//URL to test service
url: 'http://localhost:56119/PropertyAppraiser/PABusinessSearchService.asmx/searchBusinesses?NAME=' + myQuery + '&callback=JSON_CALLBACK',
header: { 'Content-Type': 'application/json; charset=utf-8' }
})
.success(function(data){
$scope.businesses = data;
});
break;
case 'address':
$http({method:'jsonp',
//URL to test service
url:'http://localhost:56119/PropertyAppraiser/PABusinessSearchService.asmx/searchAddress?myAddress=' + myQuery + '&callback=JSON_CALLBACK',
header:{'Content-Type':'application/json; charset=utf-8'}
})
.success(function(data){
$scope.businesses = data;
})
.error(function(data){
return false;
})
break;
}
})
myApp.controller('details', details = function($scope, $http, $routeParams){
var query = $routeParams.query;
var myQuery = query.indexOf('-') > 0 ? $scope.removeDashes(query):query;
$http({ method: 'jsonp',
//URL to test service
url: 'http://localhost:56119/PropertyAppraiser/PABusinessSearchService.asmx/searchBusinesses?FOLIO=' + myQuery + '&callback=JSON_CALLBACK',
header: { 'Content-Type': 'application/json; charset=utf-8' }
})
.success(function(data){
$scope.businesses = data;
});
});
This is the HTML for the app:
<div id="ng-app" class="ng-app:myApp ng-cloak" ng-cloak ng-app="myApp" ng-controller="businessSearchCtrl">
<div id="infoContainer" >
<h1 id="mainHeader">Personal Property Account Information</h1>
<div id="searchContainer">
<h3 style="background: none; margin: 0; padding: 0">Search By Folio, Business Name, or Address:</h3>
<select ng-model="chosen" ng-options="i.id as i.name for i in items">
<option value=""></option>
</select>
<input id="searchBox" type="text" placeholder="Enter Business Name or Folio Number" ng-model="query" />
<input id="submit" type="button" ng:click="search()" value="Search"/>
</div>
<div class="ng-view">
</div>
</div>
<div style="clear:both; height:0"> </div>
</div>
<div style="clear:both; height:0"> </div>
</div>
EDIT:
It works in every other browser I've tested it in including IE9, I'm also not getting any error messages.
Ok, I'm posting this answer in case any other sleep deprived fathers are out there making the same types of mistakes. The html for the partial that is being included needs to have a containing element of some sort. Apparently, IE 7 and 8 can't append the html to a page unless it is completely contained inside of a block-level element.
Maybe I knew this already and simply forgot. Maybe you knew this if you're reading this now. Maybe this is why people don't use their real names for Q&A sites. What I know for sure is, front end development can be a cruel, harsh mistress...

Resources