using resolve in a ui router parent state - angularjs

i was trying to use Angular JS to consume web api of a simple patient DB , where each patient is having a list of medications.
each of the medication and the patient has its own add , edit and list actions.
when i tried to make the edit of a patient, i have added the option of adding a new medicine(this should also be sort of editing the patient entry).
so i have used the nest state concept of nested states, where the patient edit is the parent state, while the patientedit.Medications is the child state as follows:
.state("patientEdit", {
abstract: true ,
url: "/patient/edit/:PatID",
templateUrl: "app/patients/patientEditView.html",
controller: "PatientEditCtrl as vm",
resolve: {
patientResource: "patientResource",
patient: function (patientResource, $stateParams) {
console.log("the value of PatID is " + PatID);
console.log("Patient Edit is called ???")
return patientResource.get(
{ PatID: PatID }).$promise;
}
}
})
.state("patientEdit.Medications", {
url: "/medications/:MedID/:PatID",
templateUrl: "app/patients/patientEditMedicationsView.html",
controller: "medicationEditCtrl as vm",
resolve: {
medicationResource: "medicationResource",
medication: function (medicationResource, $stateParams) {
var MedID = $stateParams.MedID;
var PatID = $stateParams.PatID;
console.log("the value of PatID is " + PatID);
console.log("the value of MedID is " + MedID);
console.log("Medication Edit is called ???");
return medicationResource.getMedication(
{ MedID: MedID, PatID: PatID }).$promise;
}
}
})
i transition to the create medicine (which is the child state in the code above as follows ) when clicking a button in the patient detail view
<a class="btn btn-primary"
data-ui-sref="patientEdit.Medications({MedID: 0, PatID: vm.patient.ID})"
style="width:160px">
Creat New Medicine
</a>
i have known from several posts here in stack over flow and the documentation of nested states that child state would wait till resolution of parent state , and also that i can use the resolved parent object from the parent state in the child state and controller.
what happens is that after i click the button for new medicine , and according to the network tab in the development tools both patient in parent state and medication in child state has been resolved correctly (according to the Response tab of the network of dev tools), but there is no transition
happening anywhere.
Edit
here is the Controllers for the aforementioned states that I'm using:
patientEditCtrl.JS:
(function () {
angular.module("patientManagement")
.controller("PatientEditCtrl",
[ "patient", "$state", PatientEditCtrl]);
function PatientEditCtrl(patient, $state) {
var vm = this;
// vm.title = "Editing";
vm.patient = patient;
if (patient == null)
{
vm.title = "New medication";
}
else {
console.log("here is the Parent controller of editing");
if ( (vm.patient.ID ) ) {
console.log("here is the controller of editing");
vm.title = "Edit: " + vm.patient.Name;
}
else {
console.log(vm.patient.Id);
vm.title = "New Patient";
}
}
vm.submit = function () {
vm.patient.$save();
}
vm.cancel = function () {
$state.go('patientList');
}
}
}());
medicationEditCtrl.Js
(function () {
angular.module("patientManagement")
.controller("medicationEditCtrl",
["medication", "$state", medicationEditCtrl]);
function medicationEditCtrl(medication, $state) {
var vm = this;
vm.medication = medication;
console.log("we are in medication edit CTRL");
if ((vm.medication.MedID)) {
console.log("here is the controller of editing a medication ");
vm.title = "Edit: " + vm.medication.Name;
}
else {
console.log(vm.medication.MedID);
console.log("having a patientId of " + vm.medication.PatID);
vm.title = "New Medication";
}
vm.submit = function () {
vm.medication.$save();
}
vm.cancel = function () {
$state.go('patientList');
}
}
}());

here is the service that i was using :
(function () {
"use strict";
angular.module("common.services")
.factory("patientResource", ["$resource", patientResource]);
function patientResource($resource) {
console.log("service is called");
return $resource("http://localhost:49190/api/patients/:Id");
};
}());
while i was calling it using (PatId), so the required solution was to change the service call in the resolve of the state named "patientEdit" to be as follows:
return patientResource.get({ Id: PatID }).$promise;
thanks again for your time and replies

Related

Redirection error in angularjs

After adding data in location table, clicking on the save button should redirect it to list of data in location table.But ,it stays in the same page after adding.The same path is given to modify location,it works fine. whereas the same path does not redirect when add location.
function locationController($scope, $state, $rootScope, locationServices,$location, locations, location, primaryLocation, $stateParams,locationTypes, countries) {
var vm = this;
$scope.locations = locations.data;
$scope.location = location.data;
if (primaryLocation.data && primaryLocation.data[0])
$scope.primaryLocation = primaryLocation.data[0];
if (!$scope.location) {
var location = {};
if ($stateParams.accountId) {
$scope.location = {accountId: $stateParams.accountId };
} else {
$scope.location = location;
}
}
$rootScope.title = "Locations";
$scope.locationslist = "views/locations.html";
$scope.addOrModifyLocation = function (location) {
if (location._id) {
locationServices.modifyLocation(location).then(function (response) {
$location.path('/account/locations/contacts/' + location.accountId + '/' +location.accountId);
// $state.reload();
})
} else {
location.status = 'ACTIVE';
locationServices.addLocation(location).then(function (response) {
$location.path('/account/locations/contacts/' + location.accountId + '/' +location.accountId);
})
}
};
If you want angular to know about your $location update, you have to do it like this :
$rootScope.$apply(function() {
$location.path("/my-path"); // path must start with leading /
});
If you're using ui-router, a cleaner approach would be to use
$state.go('stateName', {'accountId' : location.accountId, });
edit :
If you have errors that happen during a state change, you can see it by adding the following code in your app after declaring your module :
angular.module("appName").run([
"$rootScope",
function ($rootScope) {
$rootScope.$on("$stateChangeError", function(error) {
console.log(error);
});
}
]);

Access to ngSanitize in child components

I am trying to use ng-bind-html in a child component and it is not working. From what I read, You need to include ngSanitize. Which I have on am parent component and works fine there but can't get it to work on the child. Any ideas? Please let me know if you need more information. Thanks in advance!
var myApp = angular.module('subPackages', ['ngMaterial', 'ngMessages','ngSanitize']).config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow same origin resource loads.
'self',
// Allow loading from our assets domain. Notice the difference between * and **.
'<<Protected Content>>**'
]);
});
(function (app) {
'use strict';
app.component('appComponent', {
templateUrl: '../subpackages/templates/app-template.html',
controller: subAppController
});
app.component('cartSummary', {
templateUrl: '../subpackages/templates/cart-summary.template.html',
controller: cartSummaryController,
bindings: {
contentJson: '<',
cartPerfs: '<',
getGlobalContent: '&',
myNewHtml: '&',
callExecLocalProd: '&'
},
});
})(myApp);
Parent
function subAppController($sce, $compile) {
...
}
Child
function cartSummaryController($sce, $compile) {
this.$onInit = function () {
//Get content from Parent
this.globalContent = this.getGlobalContent;
this.cartSummary = this.cartPerfs;
this.myHtml = this.myNewHtml;
this.localProd = this.callExecLocalProd;
this.removePerf = function (obj) {
console.log("removing performance");
var liseqno = $("#mBtnRemove").data("liseqno");
var perfno = $("#mBtnRemove").data("perfno");
//Close modal
$('#myModal').modal('toggle');
var rpParam = [
{ elp_remove_li_seq_no: liseqno, elp_remove_perf_no: perfno }
]
this.localProd({ item: rpParam });
}
}; //End $onInit
this.confirmDelete = function (perf) {
console.log("Confirm Delete");
console.log(perf);
//Replace the perf_desc token with perf description
var msg = this.globalContent({ module: "subpackage", item: "modalMessage" });
var finalDesc = msg.replace(/{perf_desc}/g, perf.perf_desc);
//Set the body of the modal with our message
//$('.modal-body ').text($sce.trustAsHtml(finalDesc));
//$('.cs-modal-body').attr("ng-bind-html", $sce.trustAsHtml(finalDesc));
$('.cs-modal-body').attr("ng-bind-html", finalDesc);
//populate our data attributes that we will need later
$('#mBtnRemove').data("liseqno", perf.li_seq_no)
$('#mBtnRemove').data("perfno", perf.perf_no)
$('#myModal').modal();
}
}
In my html I am using
<p class="cs-modal-body" ng-bind-html="Here"></p>
if you use ng-bind-html="Here", then "Here" should be defined somewhere in your scope/context - it should be a string, which angular will try to parse as html
Define it in the controller.

How to update select tag in parent controller on emitting from child controller in AngularJS

I am new to AngularJS. In my parentController I have added a div that contains select to get emloyeeList from Database. And in childController, I am creating new Employee. After employee created, I want to emit this employee to parentController and update select tag.
Below is what I tried.
mainApp.
controller(
"childController",
['$scope', 'EmployeeFactory', 'CommonFactory', 'EmployeeFactory',
function ($scope, EmployeeFactory, CommonFactory, EmployeeFactory) {
$scope.CreateEmployee = function (newEmployee) {
var response = EmployeeFactory.CreateEmployee($scope.newEmployee);
response.success(function (successData) {
alert(JSON.stringify(successData));
$scope.GetEmployeeList = function () {
EmployeeFactory.GetEmployeeList().success(function (data) {
alert("empCreated-------emit");
$scope.$emit('getEmployeeAfterCreate --- emit-----', { getEmployeeAfterCreate: data });
}).error(function (data) {
alert("getEmpAfterCreate ---- emit-----" + data);
});
};
$scope.GetEmployeeList();
});
response.error(function (errorData) {
alert('ERROR-----------' + errorData);
});
};
}]);
mainApp.controller("parentController", ['$scope', 'EmployeeFactory', 'CommonFactory', function ($scope, EmployeeFactory, CommonFactory) {
$scope.employees = {};
$scope.$on('getEmployeeAfterCreate', function (event, args) {
alert("getEmployeeFrom Create ----------- " + JSON.stringify(args.getEmployeeAfterCreate));
$scope.employee = args.getEmployeeAfterCreate;
$scope.employees = {
ID: $scope.employee.ID,
FName: $scope.employee.FName,
LName: $scope.employee.LName,
Qualifications: $scope.employee.Qualifications,
Gender: $scope.employee.Gender,
Phone: $scope.employee.Phone,
Email: $scope.employee.Email,
Address: $scope.employee.Address,
Cities: $scope.employee.Cities
};
});
}]);
Here EmployeeFactory and CommonFactory are having methods to get and add employees.
Thanks...
In the future it might be easier to just post your actual query rather than the whole block but here's you're issue:
You registering the emitter with the name: getEmployeeAfterCreate --- emit----- and you're listening on getEmployeeAfterCreate. These names need to match otherwise there's really no way to tie the two together.
Simplified example:
var mainApp = angular.module("app", []);
mainApp.
controller(
"childController",
function($scope) {
$scope.emitter = function() {
$scope.$emit('getEmployeeAfterCreate', {
getEmployeeAfterCreate: {}
});
}
});
mainApp.controller("parentController", function($scope) {
$scope.$on('getEmployeeAfterCreate', function(event, args) {
alert("getEmployeeFrom Create ----------- ");
});
});
DEMO: http://jsfiddle.net/NfPcH/15304/

How to pass data between views using stateParameters (not routes) in AngularJS

I have some views in my applications, and I have hard time to show the data when moving from one view to another.
I have a list of news and when I click on the particular news I want the view for that particular news to be shown. Here is my code:
My app.js :
.state('app.list', {
url: "/list",
views: {
'appScreen': {
templateUrl: "list.html",
controller: 'List.Ctrl'
}
}
})
.state('app.singleview', {
url: "/list/:newsId",
views: {
'appScreen': {
templateUrl: "single.html",
controller: 'SingleCtrl'
}
}
})
My controllers:
ListCtrl.$inject = ['$http', '$scope', 'datacontext'];
function ListCtrl( $http, $scope, datacontext) {
$scope.list = [];
datacontext.getPosts().then(function (posts) {
console.log('posts', posts);
$scope.list= posts;
}, function(reason) {
alert(reason);
});
The following controller is the one which will show me the single news and I have written some code but is not correct. In the URL I get the ID but I can't manage to show the data for that ID.
SingleCtrl.$inject = ['$scope', '$stateParams', 'datacontext'];
function ListNewCtrl($scope, $stateParams, datacontext) {
$scope.New = getNewsById($stateParams.newsId);
function getNewsById(id) {
datacontext.getPosts().then(function(posts) {
var found = null;
for (var i = 0; i < posts.length; i++) {
if (posts[i].id == id) {
found = posts[i];
break;
}
}
return found;
})
}
};
So in this controller what I am trying to do is get the ID and match it with postsId, and then show the data accordingly but it does no seem to work
You're confused with the asynchronism. The code should be
getNewsById($stateParams.newsId);
function getNewsById(id) {
datacontext.getPosts().then(function(posts) {
var found = null;
for (var i = 0; i < posts.length; i++) {
if (posts[i].id == id) {
$scope.New = posts[i];
break;
}
}
});
}
So that, when the success callback is executed, the New scope variable is initialized by the found post.
That said, I have a hard time understanding why you're getting a whole list of posts from the backend instead of using a REST service returning a single post by ID. If you did, it would be reduced to
function getNewsById(id) {
datacontext.getPost(id).then(function(post) {
$scope.New = post;
});
}

Back Arrow and Angular Routing - Press Back Twice

Angularv1.1.5
Site: http://tilsa.azurewebsites.net
I have a very simple route setup however when the user goes from the default/home route to the detail (pregunta) route and then clicks the back button nothing happens. The 2nd/3rd time the back button is clicked the user returns (chrome) to the default/home route. I'm not sure as to how or why this is happening.
$routeProvider.
when('/', {
templateUrl: '/js/app/partial/index.html',
controller: 'IndexCtrl'
})
.when('/pregunta/:id', {
templateUrl: '/js/app/partial/detalle.html',
controller: 'PreguntaDetalleCtrl'
}).
otherwise({
redirectTo: '/'
});
Here are the two relevant controllers. I've removed some of the code that doesn't seem relevant (polling for new info/etc):
// load the index list of questions, the actual questions are loaded in parent scope
.controller('IndexCtrl', ['$scope', 'services', 'data', '$modal', 'navigation', 'timeFunctions', function ($scope, services, data, $modal, navigation, timeFunctions)
{
$scope.noEncodeUrl = 'http://tilsa.azurewebsites.net/';
$scope.url = encodeURIComponent($scope.noEncodeUrl);
// controls the back arrow visibility to go back
navigation.setReturn(false);
}])
.controller('PreguntaDetalleCtrl', ['$scope', '$routeParams', 'services', 'navigation', 'graphService', 'stringFx', '$timeout', 'timeFunctions', function ($scope, $routeParams, services, navigation, graphService, stringFx, $timeout, timeFunctions) {
$scope.notas = [];
$scope.comentario = '';
navigation.setReturn(true);
$scope.loadPregunta = function (id, loadComments)
{
services.preguntas.getDetalle(id).then(function (data)
{
$scope.safeApply(function ()
{
$scope.pregunta = data;
graphService.setProp('title', $scope.pregunta.pregunta);
$scope.noEncodeUrl = 'http://tilsa.azurewebsites.net/pregunta/' + id;
$scope.url = encodeURIComponent($scope.noEncodeUrl);
$scope.preguntaText = stringFx.removeAccent('¿'+$scope.pregunta.pregunta+'?');
});
if (loadComments)
{
$scope.commentTracker = {
defaults: { },
skip: 0,
take: 20
};
$scope.$on('$destroy', function (e)
{
$scope.stopPolling();
});
$scope.startPolling = function ()
{
// scrollTimeout will store the unique ID for the $setInterval instance
return $scope.scrollTimeout = timeFunctions.$setInterval(poll, 10000, $scope);
// Function called on interval with scope available
function poll($scope)
{
services.preguntas.getNotas($scope.pregunta.id, $scope.commentTracker, $scope.notas).then(function (data)
{
$scope.safeApply(function ()
{
for (i = 0, l = data.notas.length; i < l; i++)
{
$scope.notas.unshift(data.notas[i]);
}
});
});
}
}
$scope.stopPolling = function ()
{
return timeFunctions.$clearInterval($scope.scrollTimeout);
}
$scope.startPolling();
$scope.cargarAnteriores = function ()
{
//$scope.commentTracker.skip++;
services.preguntas.getNotas($scope.pregunta.id, $scope.commentTracker, $scope.notas, true).then(function (data)
{
$scope.safeApply(function ()
{
$scope.notas = $scope.notas.concat(data.notas);
$scope.masNotas = $scope.notas.length > 0;
});
});
}
$scope.cargarAnteriores();
}
});
}
$scope.notaNueva = function () {
//$scope.commentario;
if ($scope.comentario.length < 3)
{
alert('Escribe algo mas, no seas tacano con tus palabras');
return;
}
$scope.processing = true;
services.preguntas.insertNota($scope.pregunta.id, $scope.comentario, $scope.notas, false).then(function (data)
{
$scope.comentario = '';
$scope.processing = false;
$scope.loadPregunta($scope.pregunta.id, false);
services.preguntas.getNotas($scope.pregunta.id, $scope.commentTracker, $scope.notas).then(function (data)
{
$scope.safeApply(function ()
{
for (i = 0, l = data.notas.length; i < l; i++)
{
$scope.notas.unshift(data.notas[i]);
}
});
});
});
}
$scope.loadPregunta($routeParams.id, true)
$scope.$on('updatedpregunta', function (event, obj)
{
$scope.loadPregunta(obj, false)
});
}]);
I had this issue as well! Turned ut that artur grzesiak was right! I had a iframe on my page that had a binding for its src-attribute.
<iframe src="{{selected.url}}"></iframe>
Since the default value of $scope.selected.url was null the first thing that happened was that it was loading a url called null.
After some research I found that there was a special directive for the iframe:
<iframe ng-src="{{selected.url}}"></iframe>
This change solved my is
It seems that the Angular side of your app is fine.
99% the problem is caused by some external library. For sure there is some problem with this script kVEquaeit4R (it seens to be a facebook plugin), as it fails to load some resource (404 error): The resource you are looking for has been removed, had its name changed, or is temporarily unavailable. and as a consequence a couple of further errors are generated (look at the console). And in turn it prevents the app from calling window.location.hostname.replace what actually is present in the kVEquaeit4R script.
So my suggestion is as follow: remove this fb plugin from your site and check if the routing works properly...

Resources