I have a page HTML that has a button "alta", when I click that button it shows an other template as a popup and in this popup, I need values of the first page fields.
here is the function of the button "alta" in the first controller:
function altaFiltro(){
//pop up
alert(vm.filtros.codigo);
$uibModal.open({
templateUrl : 'app/entities/peticion/altaFiltro.html',
size : 'md', // sm, md, lg
controller: "FiltrosCtrl",
controllerAs : 'fil',resolve: {
filtrosVm : function() {
return vm.filtros.codigo
}
}
});
}
in the controller "FiltrosCtrl" of my template model i have:
angular.module('mecenzApp').controller('FiltrosCtrl', FiltrosCtrl);
FiltrosCtrl.$inject = [ '$scope','$uibModalInstance','Filtros'];
function FiltrosCtrl($scope, $uibModalInstance,Filtros, filtrosVm) {
var fil = this;
fil.cancelar = cancelar;
function cancelar() {
$uibModalInstance.close();
};
fil.guardar = guardar;
function guardar(){
alert(filtrosVm);
if(fil.filtros.nombre!=null){
Filtros.update(fil.filtros);
$uibModalInstance.close();
}
}
}
so I want to get the vm.filtros.codigo value but it gives me an error saying that it's not defined and this is normal because it is not defined in this sub-controller (if I can call it like that)
You could use the resolve property to solve this.
$uibModal.open({
templateUrl : 'app/entities/peticion/altaFiltro.html',
size : 'md', // sm, md, lg
controller: "FiltrosCtrl",
controllerAs : 'fil',
resolve: {
filtrosVm : function() {
return vm.filtros.codigo
}
}
});
Then filtrosVm will appear as a dependency for your Modals's controller.
function FiltrosCtrl($scope, $uibModalInstance,Filtros, filtrosVm) {
var fil = this;
fil.cancelar = cancelar;
function cancelar() {
$uibModalInstance.close();
};
fil.guardar = guardar;
function guardar(){
alert(filtrosVm);
if(fil.filtros.nombre!=null){
Filtros.update(fil.filtros);
$uibModalInstance.close();
}
}
}
You pass items to the modal instance by using resolve:
Much like this:
resolve: {
Filtros: function () {
return $scope.Filtros;
}
}
Here is a Plunk that does that
finaly it works now i get 2 fields values here is the code:
parent controller:
vm.altaFiltro = altaFiltro;
function altaFiltro(){
//pop up
alert(vm.filtros.codigo+"/iniciativa="+vm.filtros.nombreinic);
$uibModal.open({
templateUrl : 'app/entities/peticion/altaFiltro.html',
size : 'md', // sm, md, lg
controller: "FiltrosCtrl",
controllerAs : 'vm',
resolve : {
codigo : function() {
return vm.filtros.codigo;
} ,
iniciativa : function() {
return vm.filtros.nombreinic;
} ,
}
});
}
model controller:
FiltrosCtrl.$inject = [ '$scope','$uibModalInstance','Filtros','codigo','iniciativa'];
function FiltrosCtrl($scope, $uibModalInstance, Filtros,codigo,iniciativa) {
var vm = this;
vm.cancelar = cancelar;
function cancelar() {
$uibModalInstance.close();
};
vm.guardar = guardar;
function guardar(){
alert("GUARDAR:"+codigo+"/iniciativa="+iniciativa);
vm.filtros.codigo = codigo;
vm.filtros.nombreinic = iniciativa;
if(vm.filtros.nombre!=null){
Filtros.update(vm.filtros);
$uibModalInstance.close();
}
}
}
Thank you so much guys !
Related
I have the following code. It checks a factory that polls a server every few minutes. It works fine, but I want to pause the "fetchDataContinously" method when a modal is opened, and resume it when the modal is closed. In short, I need to find a way to toggle the "fetchDataContinously" on the opening and closing of modals. Please advise, or let me know if my question is not clear.
angular.module('NavBar', []).controller('NavBarCtrl', function NavBarCtrl($scope,$modal,$timeout,MyPollingService) {
var ctrl = this;
fetchDataContinously ();
function fetchDataContinously () {
MyPollingService.poll().then(function(data) {
if(data.response[0].messages[0].important_popup){
ctrl.showImportantNotice(data.response[0].messages[0]);
return;
}
$timeout(fetchDataContinously, 3000);
});
}
ctrl.showNotices = function () {
var noticesModalOptions = {
templateUrl: "notices.html",
controller: "NoticesCtrl",
controllerAs: "ctrl",
show: true,
scope: $scope,
resolve: {
notices: function(NoticesFactory) {
return NoticesFactory.getMessages();
}
}
}
var myNoticesModal = $modal(noticesModalOptions);
myNoticesModal.$promise.then(myNoticesModal.show);
}
ctrl.showImportantNotice = function (importantNotice) {
ctrl.importantNotice = importantNotice;
var importantNoticeModalOptions = {
templateUrl: "/importantNotice.html",
controller: "ImportantNoticeCtrl",
controllerAs: "ctrl",
show: true,
scope: $scope,
onHide: function() {
console.log("Close !");
fetchDataContinously();
},
onShow: function() {
console.log("Open !");
}
}
var myImportantNoticeModal = $modal(importantNoticeModalOptions);
myImportantNoticeModal.$promise.then(myImportantNoticeModal.show);
}
})
Wrap your $timeout in function and return it's promise
var timer;
function startPolling(){
return $timeout(pollData, 3000);
}
// start it up
timer = startPolling();
To cancel:
$timeout.cancel(timer);
Then to start again :
timer = startPolling();
Here is code:
Directive code:
angular.module('app', ['localytics.directives', 'ngLoadScript'])
.directive("home", function() {
return {
restrict: "A",
replace: true,
template: "<div ng-include='var'>{{var}}</div>",
controller: function($scope) {
//loading home page - as default
$scope.var = "/tfm/home.html"
//on change the page changed dynamically!
$scope.change = function(where) {
$scope.var = where;
}
}
}
})
I WANT TO CALL chanage(where) FUNCTION OF DIRECTIVE - DEFINED IN CONTROLLER OF DIRECTIVE.
Controller Code:
.controller('wToEatController', ['$scope', function($scope) {
$scope.submitInfoAboutTable = function() {
//validation for time selection
if($scope.idealTableTime == undefined || $scope.rightTableTime == undefined) {
return;
}
//Booking details to be updated - here users preference is updating!
var bookingDetails = {
idealTableWaitTime: $scope.idealTableTime,
rightTableWaitTime: $scope.rightTableTime
}
//Let's update booking information - the booking key will be same used while login, public/tfm.html
FirebaseDbService.updateBooking(function(isUpdated) {
console.log(isUpdated);
//I WANT TO CALL chanage(where) function of DIRECTIVE
$scope.change = "change('/tfm/home.html')";
}, bookingDetails, bookingKey);
}
}]);
Is it possible?
You have to create an attribute with which the link will be done (in this example customAttr):
<span yourDirectiveName customAttr="myFunctionLink(funcInDirective)"></span>
And into your directive controller just set the new attribute like in the following snippet( '&' two way data binding ) , and create a connection with your directive method :
scope : {customAttr : '&'},
link : function(scope,element,attrs){
scope.myDirectiveFunc = function(){
console.log("my directive function was called");}
}
scope.customAttr({funcInDirective : scope.myDirectiveFunc});
}
And in your controller :
$scope.myFunctionLink = function(funcInDirective){
$scope.callableDirectiveFunc = funcInDirective;}
Now you can call your directive function with $scope.callableDirectiveFunc();
I have a main controller in which I load data into a "angular-ui-grid" and where I use a bootstrap modal form to modify detail data, calling ng-dlbclick in a modified row template :
app.controller('MainController', function ($scope, $modal, $log, SubjectService) {
var vm = this;
gridDataBindings();
//Function to load all records
function gridDataBindings() {
var subjectListGet = SubjectService.getSubjects(); //Call WebApi by a service
subjectListGet.then(function (result) {
$scope.resultData = result.data;
}, function (ex) {
$log.error('Subject GET error', ex);
});
$scope.gridOptions = { //grid definition
columnDefs: [
{ name: 'Id', field: 'Id' }
],
data: 'resultData',
rowTemplate: "<div ng-dblclick=\"grid.appScope.editRow(grid,row)\" ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" ui-grid-cell></div>"
};
$scope.editRow = function (grid, row) { //edit row
$modal.open({
templateUrl: 'ngTemplate/SubjectDetail.aspx',
controller: 'RowEditCtrl',
controllerAs: 'vm',
windowClass: 'app-modal-window',
resolve: {
grid: function () { return grid; },
row: function () { return row; }
}
});
}
});
In the controller 'RowEditCtrl' I perform the insert/update operation and on the save function I want to rebind the grid after insert/update operation. This is the code :
app.controller('RowEditCtrl', function ($modalInstance, $log, grid, row, SubjectService) {
var vm = this;
vm.entity = angular.copy(row.entity);
vm.save = save;
function save() {
if (vm.entity.Id === '-1') {
var promisePost = SubjectService.post(vm.entity);
promisePost.then(function (result) {
//GRID REBIND ?????
}, function (ex) {
$log.error("Subject POST error",ex);
});
}
else {
var promisePut = SubjectService.put(vm.entity.Id, vm.entity);
promisePut.then(function (result) {
//row.entity = angular.extend(row.entity, vm.entity);
//CORRECT WAY?
}, function (ex) {
$log.error("Subject PUT error",ex);
});
}
$modalInstance.close(row.entity);
}
});
I tried grid.refresh() or grid.data.push() but seems that all operation on the 'grid' parameter is undefinied.
Which is the best method for rebind/refresh an ui-grid from a bootstrap modal ?
I finally solved in this way:
In RowEditCtrl
var promisePost = SubjectService.post(vm.entity);
promisePost.then(function (result) {
vm.entity.Id = result.data;
row.entity = angular.extend(row.entity, vm.entity);
$modalInstance.close({ type: "insert", result: row.entity });
}, function (ex) {
$log.error("Subject POST error",ex);
});
In MainController
modalInstance.result.then(function (opts) {
if (opts.type === "insert") {
$log.info("data push");
$scope.resultData.push(opts.result);
}
else {
$log.info("not insert");
}
});
The grid that received inside RowEditCtrl is not by reference, so it wont help to refresh inside the RowEditCtrl.
Instead do it right after the modal promise resolve in your MainController.
like this:
var modalInstance = $modal.open({ ...});
modalInstance.result.then(function (result) {
grid.refresh() or grid.data.push()
});
Im' working on the Malhar Angular Dashboard, based on this github project https://github.com/DataTorrent/malhar-angular-dashboard.
As per the documentation in the link post just above, under the 'dataModelType' heading 1/2 way down:
`The best way to provide data to a widget is to specify a dataModelType in the Widget Definition Object (above). This function is used as a constructor whenever a new widget is instantiated on the page.`
And when setting up the Widget Definition Objects, there are various options to choose from :
templateUrl - URL of template to use for widget content
template - String template (ignored if templateUrl is present)
directive - HTML-injectable directive name (eg. "ng-show")
So when I add my own widget definition column chart, I attempt to use the 'template' option; however it does NOT inject the {{value}} scope variable I'm setting.
Using the original datamodel sample widget def, it works fine using the 'directive' option. If I mimic this method on my column chart definition then it works ! But it doesn't work using the template option.
Here's the 'widgetDefinitions' factory code :
(function () {
'use strict';
angular.module('rage')
.factory('widgetDefinitions', ['RandomDataModel','GadgetDataModel', widgetDefinitions])
function widgetDefinitions(RandomDataModel, GadgetDataModel) {
return [
{
name: 'datamodel',
directive: 'wt-scope-watch',
dataAttrName: 'value',
dataModelType: RandomDataModel // GOTTA FIGURE THIS OUT !! -BM:
},
{
name: 'column chart',
title: 'Column Chart',
template: '<div>Chart Gadget Here {{value}}</div>',
dataAttrName: 'value',
size: {width: '40%',height: '200px'},
dataModelType: ColumnChartDataModel
},
];
}
})();
and here are the factories:
'use strict';
angular.module('rage')
.factory('TreeGridDataModel', function (WidgetDataModel, gadgetInitService) {
function TreeGridDataModel() {
}
TreeGridDataModel.prototype = Object.create(WidgetDataModel.prototype);
TreeGridDataModel.prototype.constructor = WidgetDataModel;
angular.extend(TreeGridDataModel.prototype, {
init: function () {
var dataModelOptions = this.dataModelOptions;
this.limit = (dataModelOptions && dataModelOptions.limit) ? dataModelOptions.limit : 100;
this.treeGridActive = true;
//this.treeGridOptions = {};
this.updateScope('THIS IS A TreeGridDataModel...'); // see WidgetDataModel factory
},
updateLimit: function (limit) {
this.dataModelOptions = this.dataModelOptions ? this.dataModelOptions : {};
this.dataModelOptions.limit = limit;
this.limit = limit;
},
destroy: function () {
WidgetDataModel.prototype.destroy.call(this);
}
});
return TreeGridDataModel;
});
'use strict';
angular.module('rage')
.factory('ColumnChartDataModel', function (WidgetDataModel) {
function ColumnChartDataModel() {
}
ColumnChartDataModel.prototype = Object.create(WidgetDataModel.prototype);
ColumnChartDataModel.prototype.constructor = WidgetDataModel;
angular.extend(ColumnChartDataModel.prototype, {
init: function () {
var dataModelOptions = this.dataModelOptions;
this.limit = (dataModelOptions && dataModelOptions.limit) ? dataModelOptions.limit : 100;
this.treeGridActive = true;
var value = 'THIS IS A ColChartDataModel...';
//$scope.value = value;
this.updateScope(value); // see WidgetDataModel factory
},
updateLimit: function (limit) {
this.dataModelOptions = this.dataModelOptions ? this.dataModelOptions : {};
this.dataModelOptions.limit = limit;
this.limit = limit;
},
destroy: function () {
WidgetDataModel.prototype.destroy.call(this);
}
});
return ColumnChartDataModel;
});
and finally the directives:
'use strict';
angular.module('rage')
.directive('wtTime', function ($interval) {
return {
restrict: 'A',
scope: true,
replace: true,
template: '<div>Time<div class="alert alert-success">{{time}}</div></div>',
link: function (scope) {
function update() {
scope.time = new Date().toLocaleTimeString();
}
update();
var promise = $interval(update, 500);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
}
};
})
.directive('wtScopeWatch', function () {
return {
restrict: 'A',
replace: true,
template: '<div>Value<div class="alert alert-info">{{value}}</div></div>',
scope: {
value: '=value'
}
};
})
.directive('wtFluid', function () {
return {
restrict: 'A',
replace: true,
templateUrl: 'app/views/template2/fluid.html',
scope: true,
controller: function ($scope) {
$scope.$on('widgetResized', function (event, size) {
$scope.width = size.width || $scope.width;
$scope.height = size.height || $scope.height;
});
}
};
});
I'd like to know why ONLY the directive option will update the wigdet's data and not the template option.
thank you,
Bob
I believe I see the problem. The dataAttrName setting and updateScope method are actually doing something other than what you're expecting.
Look at the makeTemplateString function here. This is what ultimately builds your widget's template. You should notice that if you supply a template, the dataAttrName does not even get used.
Next, take a look at what updateScope does, and keep in mind that you can override this function in your own data model to do what you really want, a la:
angular.extend(TreeGridDataModel.prototype, {
init: function() {...},
destroy: function() {...},
updateScope: function(data) {
// I don't see this "main" object defined anywhere, I'm just going
// off your treegrid.html template, which has jqx-settings="main.treeGridOptions"
this.widgetScope.main = { treeGridOptions: data };
// Doing it without main, you could just do:
// this.widgetScope.treeGridOptions = data;
// And then update your treegrid.html file to be:
// <div id="treeGrid" jqx-tree-grid jqx-settings="treeGridOptions"></div>
}
});
I am using the ui-router module and have defined these states:
.state('projects.create', {
url: '/create',
views: {
'outer#': {
templateUrl: 'views/projects.create.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.createSchoolyear();
}
},
controller: 'ProjectWizardController'
}
}
})
.state('projects.edit', {
url: '/edit',
views: {
'outer#': {
templateUrl: 'views/projects.edit.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.editSchoolyear();
}
},
controller: 'ProjectWizardController'
}
}
})
As each of both ui-router states know which states they are they also know what dependencies should be passed to the ProjectWizardController.
When the projects.create state is activated I want to pass the CreateWizardDataService to the ProjectWizardController.
When the projects.edit state is activated I want to pass the EditWizardDataService to the ProjectWizardController.
HOW can I manually inject the service dependency into the ProjectsWizardController?
'use strict';
angular.module('schoolyearProjectModule').controller('ProjectWizardController',
function ($scope, wizardDataService, $state, schoolyear) {
// wizardDataService => could be the CreateWizardDataService or EditWizardDataService
// The wizardDataService is the individual service for an AddService or EditService
// service contain the 3 same main properties: schoolyearData, schoolclasscodesData, timetableData
wizardDataService.schoolyearData = schoolyear.schoolyearData;
wizardDataService.schoolyearData = schoolyear.schoolclassCodesData;
wizardDataService.schoolyearData = schoolyear.timetableData;
// The if and else if should be injected into this Controller becaue the outside ui router states know their state edit/create
if ($state.current.name === 'projects.create') {
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
}
else if ($state.current.name === 'projects.edit') {
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
}
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
$scope.activeStep = $scope.steps[0];
$scope.step = 0;
var stepsLength = $scope.steps.length;
$scope.isLastStep = function () {
return $scope.step === (stepsLength - 1);
};
$scope.isFirstStep = function () {
return $scope.step === 0;
};
$scope.getCurrentStep = function () {
return $scope.activeStep.name;
};
$scope.getNextLabel = function () {
return ($scope.isLastStep()) ? 'Submit' : 'Next';
};
$scope.previous = function () {
if ($scope.step > 0) {
$scope.step--;
$scope.activeStep = $scope.steps[$scope.step];
}
};
$scope.next = function () {
if ($scope.isLastStep() && $scope.activeStep.isValid()) {
$state.go('^');
}
else if ($scope.activeStep.isValid()) {
$scope.step += 1;
$scope.activeStep = $scope.steps[$scope.step];
}
}
});
You have two ways to do this:
Option 1 - Use resolve with a string as the value. As per the documentation:
The resolve property is a map object. The map object contains
key/value pairs of:
key – {string}: a name of a dependency to be injected into the
controller.
factory - {string|function}: If string, then it is an
alias for a service. Otherwise if function, then it is injected and
the return value is treated as the dependency. If the result is a
promise, it is resolved before the controller is instantiated and its
value is injected into the controller.
Option 1 example:
.state('projects.create', {
url: '/create',
views: {
'outer#': {
templateUrl: 'views/projects.create.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.createSchoolyear();
},
wizardDataService: 'CreateWizardDataService'
},
controller: 'ProjectWizardController'
}
}
})
.state('projects.edit', {
url: '/edit',
views: {
'outer#': {
templateUrl: 'views/projects.edit.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.editSchoolyear();
},
wizardDataService: 'EditWizardDataService'
},
controller: 'ProjectWizardController'
}
}
})
Option 2 - Use $injector.get('CreateWizardDataService') or $injector.get('EditWizardDataService') directly in your controller depending on which state you are in.