AngularJS - Controller values not binding - angularjs

In my MVC program simple angular value controllers values are not binding.
My code is as follows :
_Layout.cshtml
<body data-ng-app="ShoppingCartApp">
<div class="container body-content">
#RenderBody()
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/Scripts/angular.js")
#Scripts.Render("~/Scripts/Custom/App.js")
#Scripts.Render("~/Scripts/Custom/ShoppingCartController.js")
#RenderSection("scripts", required: false)
<hr />
</div>
</body>
App.js
var app = angular.module('ShoppingCartApp', []);
ShoppingCartController.js
app.controller('ShoppingCartController', function ShoppingCartController($scope, $http) {
$scope.ShoppingCartObj.products = [];
$scope.test = "ABC";
// On load events
// $scope.loadValues();
});
My Html Code is follows :
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script></script>
<h2>Index</h2>
Total {{2+2}} // This value workd FINE
<div ng-controller="ShoppingCartController">
<div class="row">
<div class="nav navbar-nav navbar-left">
<h3>Total {{2+2}}</h3> // Not working THIS
</div>
<h1>{{test}}</h1> // Not working THIS
</div>
</div>
When i try to access value in controller or access directive inside controller it's not working. What i miss in here?

Change your controller to:
app.controller('ShoppingCartController', function($scope, $http) {....});
Or create a function named ShoppingCartController and then pass it to controller:
app.controller('ShoppingCartController', ShoppingCartController);
Also change $scope.ShoppingCartObj.products to $scope.ShoppingCartObj = {}; and then add products to that object $scope.ShoppingCartObj.products = []; because, prev you havnt defined what $scope.ShoppingCartObj is, so this object will be undefined.

If you're using Bundler you need to specify the Dependency Injection values
Also - ShoppingCartObj isn't declared anywhere so you can't assign to a property products
app.controller('ShoppingCartController', ['$scope', '$http',
function ShoppingCartController($scope, $http) {
$scope.ShoppingCartObj = {},
$scope.ShoppingCartObj.products = [];
$scope.test = "ABC";
}]);
Here's a working Jsfiddle

Related

Cannot read property 'nid' of undefined, need to pass object to another controller

I'm having issues trying to pass a selected value from one controller to another controller.
View (I pass the NgValue to $scope in Controller).
<li class="list-group-item" ng-repeat="item in filterData = (informes | filter:{title:searchTitle, resolucion:searchReso, year: searchYear}) | limitTo:10:10*(currentPage-1)">
<div class="wrapper">
<div class="informes" ng-value="nodeID(item)">
<a ng-href="../node-informes/node-informes.html">
<p class="text-center text-truncate">
<small>{{item.title}}</small>
</p>
</a>
</div>
</div>
</li>
Controller. I have the "Item in that Controller" and the console prints it.
informes.controller('InformesCtrl', ['drupal', '$rootScope', '$scope', '$http', 'InformesFtry', function(drupal, $rootScope, $scope, $http, InformesFtry) {
$rootScope.getData = function(informes){
$rootScope.nodeID = function(item){
$rootScope.node = item.nid;
console.log($rootScope.node);
};
}
}]);
2nd Controller in another module (gives me "Cannot read property 'nid' of undefined" error").
nodeInformes.controller('NodeInformesCtrl', ['$rootScope', '$scope', '$http', '$controller', function($rootScope, $scope, $http, $controller) {
$controller('InformesCtrl', {$scope: $scope});
$rootScope.getData(informes);
$rootScope.nodeID(item);
$scope.node = $rootScope.node;
console.log($scope.node);
}]);
It supposed that i called the other controller with parameters (saved value in "$rootScope.node", passed it to 2nd controller, but it gives me the error that's undefined).
consolelog in first controller works, but not in second controller.
I appreciate any suggestion.
Modified as code suggested, but seems that the "item" object is not passing the right way.
Try to avoid using $rootScope unless you absolutely have to (raising or handling events is about the only time I've ever used $rootScope) - instead you can use a service to reliably pass data between controllers. In AngularJS services are singletons so all of your controllers have access to the same instance. You can take advantage of this and use the service to "pass" (more accurately share) data between controllers.
Here is a simple example to demonstrate the concept which you can then apply to your situation. Normally you wouldn't have two controllers in a single view like this, but for illustration purposes (and being able to run in the SO snippet engine) I've done it here. Just to prove that I'm not sharing any controller variables I've named them differently.
angular.module('app', [])
.service('sharedService', function() {
var service = {};
service.sharedObject = {};
service.sharedObject.value = "Set in service";
return service;
})
.controller('ctrlOne', function($scope, sharedService) {
$scope.sharedObjectC1 = sharedService.sharedObject;
})
.controller('ctrlTwo', function($scope, sharedService) {
$scope.sharedObjectC2 = sharedService.sharedObject;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrlOne" style="margin-bottom: 30px;">
<h1>Controller One</h1>
Modifying this value will update it in Controller Two:
<div>
<input ng-model="sharedObjectC1.value" />
</div>
</div>
<hr>
<div ng-controller="ctrlTwo">
<h1>Controller Two</h1>
Modifying this value will update it in Controller One:
<div>
<input ng-model="sharedObjectC2.value" />
</div>
</div>
</div>

angularjs dom manipulation based on button click

basically i want to change the attribute value based on the button i clicked,
these are the two buttons
<button ng-click="fn(a)"></button>
<button ng-click="fn(b)"></button>
and then i have a prebuilt directive who takes value as input,
<div directive-name="" id="abc"></div>
if i click on first button,i want the value of directive based on button clicked.
What i did earlier;
$scope.go = function(data){
if(data==a){
var b = document.querySelector( 'div' );
b.setAttribute("directive-name","value");
}
else{}
}
here the problem is that it is selecting the first div of document and setting attribute value for that.
I also tried to pass it with id like
var b = angular.element(document.querySelector('#abc'));
I also saw some custom directives to do so, but they are not working
AngularJS DOM Manipulation through Directives
If possible provide me a demo in plunkr or fiddle
and also if i want to change css property of div based on button clicked
Thanks in advance
You can do it like this.
Assign the directive-name value to a $scope.variable and then use variable as the value in HTML.
HTML - 1:
<button ng-click="go(a)"></button>
<button ng-click="go(b)"></button>
HTML - 2:
<div directive-name="{{directive}}" id="abc"></div>
JS:
$scope.go = function(data){
if(data==a){
$scope.directive = "directive-1";
}else if(data==b){
$scope.directive = "directive-2";
}
}
To assign class name to div you can define other $scope.classVar and then use that in HTML like below:
<div directive-name="{{directive}}" id="abc" ng-class="classVar"></div>
I hope this will solve your problem.
This should work, (you had some errors in your code):-
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.fn = function(data,id) {
if (data == 'a') {
var b = document.querySelector('#'+id);
b.setAttribute("directive-name", "value");
} else {
}
}
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div directive-name="" id="abc"></div>
<button ng-click="fn('a','abc')">A</button>
</div>
"Basically I want to change the attribute value based on the button I clicked."
You can do this by changing the attribute value the angular way, referencing a property of $scope or the controller instance in your template. When clicking a button, set the variable to the value you require to be passed to your directive.
Note: When you pass a value into your ngClick directive, you need to pass it as a string unless a and b are declared as properties of $scope.
Here's a basic example:
// app.js
(function() {
'use strict';
angular.module('app', []);
})();
// main.controller.js
(function() {
'use strict';
angular.module('app').controller('MainController', MainController);
MainController.$inject = ['$scope'];
function MainController($scope) {
$scope.fn = fn;
function fn(data) {
// set the value so it's accessable in the view
// therefore we can pass it into our directive
$scope.myVar = data;
}
}
})();
// directive-name.directive.js
(function() {
'use strict';
angular.module('app').directive('directiveName', directiveNameDirective);
function directiveNameDirective() {
return {
restrict: 'A',
scope: {
directiveName: '='
},
template: '<span>directiveName: {{ directiveName }}</span>'
};
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MainController as MainCtrl">
<!-- here we pass a and b as strings otherwise they get evaluated as variables -->
<button ng-click="fn('a')">Set a</button>
<button ng-click="fn('b')">Set b</button>
<hr>
<!-- here we pass myVar which is declared as a property of $scope when the fn function is called -->
<div directive-name="myVar" id="abc"></div>
<hr> myVar: {{ myVar }}
</div>
</div>

How to pass scope variable through ng-click function?

Here when i click on cartDetails the dynamic scope variable x.SmId value need to be passed to the bellow function and in alert box need to display the parameter .How can we do this one in angular js?
<div ng-app="" ng-controller="MyCtrl">
<div ng-repeat="x in names">
<div ng-click="cartDetails('{{x.SmId}}')">
<div>{{x.name}}</div>
</div>
</div>
</div>
<script>
angular.module('MyApp', [])
.controller('MyCtrl', ['$scope', '$http', function($scope, $http) {
$scope.search = function(param) {
$http.get('AngularJs-Response.jsp?mid='+param).success(function(response) {
$scope.names = response;
});
};
$scope.cartDetails = function(smid) {
alert(smid);
};
}]);
</script>
Use simple:-
ng-click="cartDetails(x.SmId)"
I tried to use:
ng-click="cartDetails(x.SmId)"
but it simply x.SmId as string, its not replaced by value. After reading few more articles, I found a solution like below:
<div ng-click="cartDetails('{{x.SmId}}')">
Its a working solution in AngularJS v1.3.9

Controller triggered via factory

I am still a novice with angular. I have asked a question similar to this before, but it seems to be a different issue at work here.
I have two controllers and a factory sharing information between them. I have two separate divs using two different controllers to show / hide using ng=show;
HTML
<div id=main>
<div ng-controller="Ctrl1">
<div ng-show="var1">Hidden Stuff</div>
</div>
<div ng-controller="Ctrl2">
<div ng-show="var1">More Hidden Stuff</div>
</div>
</div>
Both use the same var for ng-show, shared by a factory
JS Factory
app.factory('Srvc', function($rootScope) {
var Srvc = {};
Srvc.var1;
return Srvc;
});
JS Controllers
app.controller('Ctrl1', function($scope, Srvc) {
$scope.var1 = false;
if (user interacts with html in div with ng-controller="Ctrl1") {
$scope.var1 = true;
Srve.var1 = $scope.var1;
}
});
app.controller('Ctrl2', function($scope, Srvc) {
$scope.var1 = Srvc.var1;
if ($scope.var1 === true) {
update HTML in div with ng-controller="Ctrl2"
although I shouldn't need to do this really should I?
}
});
So from what I can tell the factory works ok, the data is saved in the factory Srvc.var1. However when I pass the data true to Srvc.var1 I cannot seem to get Ctrl2 to 'trigger' and update its html with ng-show=true
One way to solve this problem without explicitly creating a watcher, is to wrap var1 in an object inside the service and then pass this object as a $scope variable for both Ctrl1 and Ctrl2 controllers.
DEMO
Javascript
.factory('Svc', function() {
var service = {
data: {}
};
// If you perform http requests or async procedures then set data.var1 here
service.data.var1 = true;
return service;
})
.controller('Ctrl1', function($scope, Svc) {
$scope.data = Svc.data;
})
.controller('Ctrl2', function($scope, Svc) {
$scope.data = Svc.data;
});
HTML
<div id="main">
<div ng-controller="Ctrl1">
<div ng-show="data.var1">Hidden Stuff</div>
<button type="button" ng-click="data.var1 = true">Set data.var1 to true</button>
<button type="button" ng-click="data.var1 = false">Set data.var1 to false</button>
</div>
<hr>
<div ng-controller="Ctrl2">
<div ng-show="data.var1">More Hidden Stuff</div>
<button type="button" ng-click="data.var1 = true">Set data.var1 to true</button>
<button type="button" ng-click="data.var1 = false">Set data.var1 to false</button>
</div>
</div>
So it seems I need to $watch the service for a change within the controller.
Original answer is here.
app.controller('Ctrl2', function($scope, Srvc) {
$scope.$watch(function () {
return Srvc.var1;
},
function(newVal, oldVal) {
$scope.var1 = newVal;
}, true);
});
I think setting Var1 to $rootScope instead of Srvc should work, just call $scope.$root.$digest() after updating var1.
and use ng-show=$root.Var1 in view.

Get error Cannot read property 'offsetWidth' when try to initiate Google maps from "run" method in Angular

I have following service that initiate Google maps:
app.service('mapService', ['$q', '$rootScope', function($q, $rootScope) {
var self = this;
var geocoder = new google.maps.Geocoder();
var streetViewService = new google.maps.StreetViewService();
self.map = false;
self.panorama = false;
self.center = null;
self.initialize = function(map_id) {
var options = {
center: new google.maps.LatLng(0, 0),
zoom: 3,
scaleControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
self.map = new google.maps.Map(document.getElementById(map_id), options);
// ^^^ here get error
};
....
My app.js looks like:
var app = angular.module('cntsApp', []); //['AngularGM']
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/mapboard', {templateUrl: config.base_url + 'app/partials/cnts.html', controller: 'CntsCtrl'});
}]);
app.run([
'$rootScope',
'$window',
'mapService',
function($rootScope, $window, mapService) {
mapService.initialize("heatmapAreaA");
}]);
As you can see I call mapService.initialize(/**/) from app.run but get Exception:
Uncaught TypeError: Cannot read property 'offsetWidth' of null
From other posts its mean that Google maps still didn't render and I need wait till DOM will finish.
How can I achieve that in my case?
[EDIT]
HTML
<div ng-controller="CntsCtrl">
<div class="container" style="width: 96%">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="row clearfix">
<div class="col-md-2 column">
Config
</div>
<div class="col-md-6 column">
<div id="heatmapAreaA" ></div>
</div>
<div class="col-md-4 column">
Chart
</div>
</div>
</div>
</div>
</div>
</div>
From controller the line: mapService.initialize("heatmapAreaA"); works fine.
Thanks,
I can't test it, but my guess is your view html hasn't completely been compiled by Angular, therefor Google Maps can't find your div to display the map in. Try putting the
mapService.initialize("heatmapAreaA");
call in a controller for your view and put the call in a $timeout:
$timeout(function(){
mapService.initialize("heatmapAreaA");
});
This way the call gets fired after the controller has run and your view has been compiled.

Resources