angularjs child controller has no access to parent - angularjs

I have Two nested controllers:
BuildingsShowCtrl = ($scope, $location, $routeParams, Building) ->
$scope.building = Building.get
id: $routeParams.id
AddressesChildCtrl = ($scope, $routeParams, Address) ->
$scope.addresses = Address.query({building_id: $scope.building.id})
They are used this way in my nested views:
<div ng-controller="BuildingsShowCtrl">
<h1>Building</h1>
<p>
<b>Name</b><br>
{{building.name}}
</p>
<p>
<b>Number</b><br>
{{building.number}}
</p>
<div ng-include="'/assets/addresses/index.html'"></div>
</div>
When I hit refresh on the browser, it works fine but when I click a building from a building lists page, it fails because $scope.building is undefined in AddressesChildCtrl.
Why doesn't the child controller have access to the parent controller's scope in this case?
The app is visible here: http://lgi.herokuapp.com/buildings/
Thx!

If you are using ngResource, Building.get will return an empty object immediately and will asynchronously fill in the object data after the HTTP request is complete (documentation). You can do something like this to load the address data when the object is filled in:
AddressesChildCtrl = function($scope, $routeParams, Address) {
$scope.$watch('building.id', function(newValue, oldValue) {
if (newValue) {
$scope.addresses = Address.query({building_id: $scope.building.id})
} else {
$scope.addresses = []
}
}, true);
}

Related

Return service $http.get response to controller without using $scope

I've been searching around for hours, but I couldn't find a solution. I'm trying to retrieve data from a separate json-file in my AngularJS application. Using the $http I do get the data I want.
However, I want to get specific data from that file at in multiple places. In the service I want to define some functions that controllers can call to retrieve the data (that the service got using $http).
Now the problem is that when I return the all the data to the controller directly, or try to use it later in the service, the assigned variables are undefined.
I try to use controller-as syntax, so I do not want to use $scope. However every solution I've found suggests using $scope. This code now logs
f {$$state: {...}}.
Code of the service:
theApp.service('SettingsService', function($http) {
this.dataVar = $http.get('../settings.json')
.then(function(response) {
return response;
});
});
Code of the controller:
theApp.controller('SomeController', ['SettingsService', function(SettingsService) {
console.log(SettingsService.dataVar);
}]);
UPDATE:
https://jsfiddle.net/md954y0a/
what about calling your service at start-up module then passing to submodules through a service that loads the same instance
html:
<div ng-app='myApp' ng-controller="myctrl">
{{parent}}
<div ng-app='myApp1' ng-controller="myctrl1">
{{myApp1data}}
</div>
</div>
js:
angular.module('myApp', ['myApp1']).controller('myctrl', ['$scope', 'API', function($scope, API) {
$scope.parent = API.getData();
}]).service('API', function($q) {
var object = null;
this.getData = function() {
object = {
obj1: "DATA1",
obj2: "DATA2"
};
return object;
}
});
angular.module('myApp1', []).controller('myctrl1', ['$scope', 'API', function($scope, API) {
$scope.myApp1data = API.getData().obj1
}]);

Ui bootstrap doesn't show after adding object to controller

So my ui bootstrap model window is working correctly but when I add an object to the controller it stops showing and it doesn't give me any error in consol.
When my controller looks like this:
"use strict";
app.controller('RegisterModalCtrl', ['$scope', '$location', '$uibModalInstance', '$http', 'ngAuthSettings', 'registerService',
function($scope, $location, $uibModalInstance, $http, ngAuthSettings, registerService) {
var $ctrl = this;
$ctrl.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
/*
$ctrl.registerInfo = {
email: $ctrl.registerData.email,
nick: $ctrl.registerData.nick,
password: $ctrl.registerData.password,
password_confirmation: $ctrl.registerData.confirm_password
};
*/
$ctrl.registerSubmit = function(registerInfo) {
console.log('im in registerSubmit controller function');
registerService.registerUser(registerInfo);
$uibModalInstance.dismiss('cancel');
};
$ctrl.showCookiesRules = function() {
$location.url("/cookiesrules");
$uibModalInstance.dismiss('cancel');
};
$ctrl.showRules = function() {
$location.url("/rules");
$uibModalInstance.dismiss('cancel');
};
}]);
Everything works just fine but when i delete /* just before registerInfo object it stops showing. What is wrong with this object? I want it to create this object to pass it in function and then pass it to function in service.
So what you should do is initiate $ctrl.registerInfo:
$ctrl.registerInfo = {};
The data doesn't exist when the controller runs, so you are trying to set the properties of $ctrl.registerInfo without non-existent data. Once your form is filled out, the properties/data will be set.
An alternative option would not be to initialize at all, and simply set your form model to registerData.confirm_password, and when you call registerSubmit, call it with registerSubmit(registerData). That will send the data to that method without having to initialize in the controller:
<input type="text" placeholder="powtórz hasło"
ng-model="registerData.confirm_password" />
<!-- abbreviated (other form fields here -->
<input type="submit" ng-click="registerSubmit(registerData)" />
If you need the data afterwards, in registerSubmit, add a line:
$ctrl.registerInfo = registerInfo;
However, I am not sure you'd want to hang onto the password there.
AngularJS Form Docs: https://docs.angularjs.org/guide/forms

AngularJs, Passing optional parameters to the URL based on user input

I am trying to consume my ASP.NET Web API using AngularJs. The problem is that i want to pass optional parameters to the url based on the user input(2 Html Text Boxes) but i don't know how.
This is my ASP.NET Web API Controller
[Route("api/JobShow/{keyword}/{location}")]
public class JobShowController : ApiController
{
[HttpGet]
public PageResult<sp_JobSearch_Result> Get(ODataQueryOptions<sp_JobSearch_Result> options, string keyword = null, string location = null)
{
ODataQuerySettings settings = new ODataQuerySettings()
{
PageSize = 20
};
JobWindow obj = new JobWindow();
IQueryable results = options.ApplyTo(obj.showJobs(keyword, location).AsQueryable(), settings);
return new PageResult<sp_JobSearch_Result>(
results as IEnumerable<sp_JobSearch_Result>,
Request.GetNextPageLink(),
Request.GetInlineCount());
}
}
And this is my AngularJS controller
angular.module('JobSearch.SiteController', []).controller('JobSearchCtrl', ['$scope', '$http', function ($scope, $http) {
$http.get('/api/JobShow').success(function (data) {
$scope.model = data;
});
}]);
Example of the url then would be .../api/JobShow/Java/Toronto. Thank you all.
You can try ngResource !
You first need to include ng-resource
<script src="angular.js">
<script src="angular-resource.js">
You can get it via Bower or CDN, or whichever way you got AngularJS.
HTML:
<body ng-app="MyApp">
<div ng-controller="MyCtrl">
<label>Keyword: <input type="text" ng-model="keyword" /></label>
<label>Location: <input type="text" ng-model="location" /></label>
<button ng-click="getJobShowPage(keyword, location)">Search</button>
</div>
</body>
Controller:
angular
.module('MyApp', ['ngResource']) // Include the ngResource module here
.controller('MyCtrl', ['$scope', '$resource', function($scope, $resource){
// Create the $resource
var JobShowPage = $resource('/api/JobShow/:keyword/:location', {keyword: "#keyword", location: "#location"})
// Make a scope function to use the resource properly
$scope.getJobShowPage = function(keyword, location) {
var parameters = {};
if (keyword) {
parameters["keyword"] = keyword;
if (location) {
parameters["location"] = location;
}
}
return JobShowPage.get(parameters);
};
}]);
Input/Outputs:
When the user enters nothing and clicks 'Search', the HTTP request would be /api/JobShow
If only the keyword is entered, the HTTP request would be /api/JobShow/{{keyword}}
If both the keyword and location is entered, the HTTP request would be /api/JobShow/{{keyword}}/{{location}}
If only the location is entered (no keyword), the HTTP request would be the vanilla one /api/JobShow
You can consume the return value of the $resource query like a promise:
JobShowPage.get(parameters).$promise.then(function(response){
// Do Stuff
$scope.model = response.data;
});
by callbacks:
JobShowPage.get(parameters, function(err, response){
// Do Stuff
$scope.model = response.data;
});
Or auto unwrap it:
// This works, but it's asynchronous
// Useful if consuming directly from the Angular Template
$scope.model = JobShowPage.get(parameters);
Based on your code, I'm going to assume you have 2 textboxes and a search button, and when the search button is pressed, you want to call your GET endpoint. For this scenario, what you'll want to do is bind the textbox inputs to your scope and bind the search button using ng-click to a function in your scope that will call your endpoint. It might look something like this:
controller
angular.module('JobSearch.SiteController', [])
.controller('JobSearchCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.getResults= getResults;
function getResults() {
$http.get('/api/JobShow/' + $scope.keyword + '/' + $scope.location).success(function (data) {
$scope.model = data;
});
}
}]);
html
<div ng-controller="JobSearchCtrl">
<input type="text" ng-model="keyword">
<input type="text" ng-model="location">
<button type="button" ng-click="getResults()">Search</button>
</div>

controller function not called from ng-click

I have a controller that ive added a function to but cant get the function to be called from ng-click on an anchor. Ive looked at similar posts but cant really see what I could be missing. Its as though the controller function cant be seen?
The module and controller:
var commonModule = angular.module('common', ['ngRoute', 'ng.ckeditor']);
var mainModule = angular.module('main', ['common']);
//mainModule.config(function ($routeProvider, $locationProvider) {
// $locationProvider.html5Mode(true);
//});
commonModule.factory('viewModelHelper', function ($http, $q, $window, $location) {
return MyApp.viewModelHelper($http, $q, $window, $location);
});
commonModule.factory('validator', function () {
return valJs.validator();
});
mainModule.controller("rootViewModel",
function ($scope, $http, $q, $routeParams, $window, $location, viewModelHelper, $rootElement) {
//test
console.log("creating controller");
var self = this;
viewModelHelper.apiGet('api/PageContent/1', null,
function (result) {
$scope.htmlEditor = result.data;
});
$scope.ToggleEditor2 = function () {
//test
console.log("hello");
if ($scope.editorVisible == true) {
$scope.editorVisible = false;
}
else {
$scope.editorVisible = true;
}
}
});
The controller is referenced at the root level of the page:
Which in this case since im using ASP.Net MVC, is in my _layout.cshtml
<body data-ng-app="main" data-ng-controller="rootViewModel">
In a (mvc) view that gets loaded, I have a button with ng-click that calls the ToggleEditor2 function, but its never called. Cant get a breakpoint to hit in the chrome dev console and I dont see anything written to the log either.
<input type="button" ng-click="ToggleEditor2()" value="test me" />
Update:
If I wrap that anchor with a div and specify the "rootviewModel" controller there, the log message gets written. Hmmm - something tells me its related to scope?
<div data-ng-controller="rootViewModel">
<input type="button" ng-click="ToggleEditor2()" value="test me" />
</div>
Problem
A common problem with $scope is that when using any sort of nested controllers or modules, your $scope's can step on each other and cause issues like you have experienced.
Solution
Using Angular's "Controller As" syntax is the recommended solution for this problem. It allows you to create multiple instances of the same controller, while defining and maintaining a unique scope for each instance.
This Article is a great resource I used to understand and implement this new syntax.

Update $scope variable that is used in ng-repeat, from other controller

I have a controller HomeworkPageController where I get all the topics from MongoDB using method getAllMainTopics from TopicService. $scope.topics is then used to show all topics. I have a button that open a modal where a new topic is add in MongoDB. The modal is using another controller AddTopicController. How can I update $scope.topics from HomeworkPageController in AddTopicController ? I want to do this because after I close the modal, the list of all topics should be refreshed, it must contain the topic that has been added. I tried to use HomeworkPageController in AddTopicController and then call the method getAllMainTopics but the $scope.topics from html is not updated. Thanks.
Here is HomeworkPageController:
app.controller('HomeworkPageController', ['$scope','TopicService',
function ($scope, TopicService) {
$scope.topics = [];
$scope.getAllMainTopics = function () {
TopicService.getAllMainTopics('homework')
.success(function(data) {
$scope.topics = data;
}
$scope.addTopic = function () {
ModalService.openModal({
template: "templates/addTopic.html",
controller: 'AddTopicController'
});
}
]);
Here is AddTopicController:
app.controller('AddTopicController', ['$scope','$controller', '$timeout','TopicService', '$modalInstance',
function ($scope, $controller, $timeout,TopicService, $modalInstance) {
var homeworkPageController = $scope.$new();
$controller('HomeworkPageController',{$scope : homeworkPageController });
$scope.save = function() {
TopicService.saveTopic(data)
.success(function(result){
homeworkPageController.getAllMainTopics();
$modalInstance.close();
})
}
}]);
Here is the view where I use $scope.topics:
<div class="homework-content-topic-list" ng-repeat="topic in topics">
<label> {{ topic.subject }} </label>
</div
You should probably keep your list of topics in a service and then inject that service into both controllers. This way you would be able to access and update the topics in both of your controllers. It could look something like
app.controller('HomeworkPageController', ['$scope','TopicService',
function ($scope, TopicService) {
$scope.topics = TopicService.topics;
// Do stuff here
]);
Then you just need to modify your TopicService to have it's methods work on the stored object.
you can solve this by two methods
1)look at the example given in ui-bootstrap's website. They have given an example that will suit your requirement - plunker. There are three items in the modal - item1, item2, item3. If you select one of those items and click 'ok', the selected item is sent to the main controller through "resolve" attribute in the $scope.open function.
2)You can write a custom service that acts as a bridge to the two controllers and you can write getter and setter methods in the service.
angular.module('app').service('popupPageService', function() {
var topics;
var setDetails = function(param) {
topics = param;
};
var getDetails = function() {
return topics;
};
return {
setDetails: setDetails,
getDetails: getDetails,
};
});
call the setDetails function in the AddTopicController and once when you come out of the modal, update your $scope.topics in HomeworkPageController by pushing the new value added (getDetails)

Resources