comunication between controllers isnt working with $scope.broadcast and $scope.on - javascript

I guys, in my previous post here I ask how to comunicate between 2 controllers, inside the same file. I have a button where I pass a name inside ng-click with a tab name. When i click in this button the goal is to open a new view in the specified tab inside ng-click.
Each controller have a view instantiated with ng-controller, so they dont share the same view.
At now I have,
dashboardController:
button inside datatable :
return icon = '<center><a class="state-link" data-state-id="' + data.id + '" ng-click="setActiveTab(\'system\')"><i style="color:#0040ff; width:21px; height:21px" title="System threshold exceed" class="fa fa-warning"></i></a></center>';
controllerScope.setActiveTab = function (name) {
console.log("setActiveTab()");
console.log("name ",name);
$rootScope.$broadcast('myCustomEvent', name);
}
dashboardDeviceController:
Here I have the var i want to change
controllerScope.activeTab = {
consumptions: true,
network : false,
ap : false,
modem : false,
system : false,
};
$rootScope.$on('myCustomEvent', function(event, data) {
console.log("myCustomEvent ", data);
for (var tabName in controllerScope.activeTab) {
if (controllerScope.activeTab[tabName] == data) {
controllerScope.activeTab[tabName] = data;
break;
}
}
});
I have a problem and when I click in the button nothing happen.. so is there a problem with $rootScope.on or $rootScope.broadcast??? I cant figure this out ...

you should use $scope to broadcast and `subscribe,
So, change controllerScope.$broadcast('myCustomEvent', name); to $scope.$broadcast('myCustomEvent', name);
controllerScope.setActiveTab = function (name) {
console.log("setActiveTab()");
console.log("name ",name);
$scope.$broadcast('myCustomEvent', name);
}

Have a look at the accepted answer here
You can either broadcast on $rootScope, to have the whole app hear it, or if you don't want to, you need to make sure that the broadcast is meant for the $scope itself and its children. In summary, one controller should be a child of the other.

Related

angularjs function called just after the first click

I have an issue with angularjs 1 and ionic is that I have a list of items , so I want to show the clicked item properties , so I tried to ways to save the id of the clicked item, but the same issue which is , just the first time after refreshing the page (while serving on laptop) I got the right clicked item properties , but if I clicked back and tried to click on another item i get the properties of the item i clicked first! why is that happening ? how can I fix this ? thank you
this is the service for storing and retrieving the id :
.service('eventID', ['$rootScope', function($rootScope) {
this.saveID = function(id) {
$rootScope.ID = id;
}
this.getID = function() {
return $rootScope.ID;
}
}]);
this is what's inside the first controller :
$scope.setMaster = function(event) {
$scope.selected = null;
$scope.selected = event.id;
eventID.saveID($scope.selected);
$state.go('detail');
}
this is what's inside the second controller where i will get the id of the selected item :
$scope.selected = eventID.getID();

How to call function in ionic angularjs with local notification

I have an application that has two buttons , Add button and Schedule button ,
When i click on the add button the notification will be triggered then the notification tab will appeared .
Here is the code
Js code
app.controller('contNoti', function ($scope, $cordovaLocalNotification)
{
$scope.add = function () {
var alarmTime = new Date();
alarmTime.setMinutes(alarmTime.getMinutes() + 1);
$cordovaLocalNotification.add({
id: "1234",
date: alarmTime,
message: "This is a message",
title: "This is a title",
autoCancel: true,
sound: null
}).then(function () {
console.log("The notification has been set");
});
};
$scope.isScheduled = function () {
$cordovaLocalNotification.isScheduled("1234").then(function (isScheduled) {
alert("Notification 1234 Scheduled: " + isScheduled);
});
};
});
<ion-content ng-controller="contNoti">
<button class="button" ng-click="add()">Add notification</button>
<button class="button" ng-click="isScheduled()">Is Scheduled</button>
</ion-content>
Ok, what I need is to make the same application with the same functionality but without the buttons. I want it to be executed automatically without clicking on the buttons. Thanks
I'm not sure I understand your question, but you want to run $scope.add() no matter what, is that correct?
If so, just add $scope.add(); after the $scope.isScheduled = function () {...}; block.
I hope that's the answer you're looking for, otherwise, please provide more details.
You could trigger your methods with the events from $ionicView:
Inside your controller:
$scope.$on('$ionicView.enter', function(data) {
$scope.add();
$scope.isScheduled();
})
They will be executed once the User enter to the view.
Note: Those functions could be private(not attached to the $scope). Because they wont be used in the View.

UI Grid refresh in Angular

From a different controller a modal pop up opens. On closing of the modal pop up , I will do something and I want to transfer the data to a different controller which populates a UI grid and is bound to $scope.searchResultsGridOptions.
So in my ABCCtrl.js file :
On closing of a modal , I do :
$("#iConfirmationModal").on('hidden.bs.modal', function () {
$state.go('transaction.search.results', {});
//I close all the modals
$uibModalStack.dismissAll();
//I get the stored search criteria
var searchResultsParam = TransactionDataServices.getSavedSearchParams();
//Using them I hit the web service again and get the data to reload the UI Grid
TransactionServices.getTransactionAdvSearchResults(searchResultsParam).then(function (result) {
//I got the result
console.log(result);
/Now I want to reload the grid with this data , but the grid scope object which binds to this , is in separate controller
searchResultsGridOptions.data = result;
});
});
In DEFCtrl.js
I have
getSearchResultsGridLayout: function (gridOptions, uiGridConstants, datas) {
gridOptions.multiSelect = false;
// gridOptions.data.length = 0;
// gridOptions.data = '';
gridOptions.data = datas;
console.log("Grid Data ");
console.log(datas);
console.log(gridOptions.data);
angular.element(document.getElementsByClassName('grid')[0]).css('height', '0px');
// console.log(datas.length);
return gridOptions;
}
But how would I only change the data only when modal closes ?
Rest of the time it should not refresh the Grid ?
Or ,
Is there any way when on closing of the modal , instead of simply go back to the state using $state.for() and seeing the previous unrefreshed data , I can see the refreshed data ?
Hi I think you do not need to call the "TransactionServices.getTransactionAdvSearchResults()" in the "ABCCtrl" controller but you have to call it in the "DEFCtrl" controller.
You need to find a way to pass the "searchResultsParam" extracted in "ABCCtrl" to "DEFCtrl".
You can use the ui-router state parameters. You can specify a parameter in the "transaction.search.results" state, like this:
.state('transaction.search.results', {
...
params: {
searchResultsParam: null
}
...
})
And in the "ABCCtrl" pass it to the state:
$("#iConfirmationModal").on('hidden.bs.modal', function () {
//I close all the modals
$uibModalStack.dismissAll();
//I get the stored search criteria
var searchResultsParam = TransactionDataServices.getSavedSearchParams();
$state.go('transaction.search.results', {searchResultsParam: searchResultsParam});
Then, in "DEFCtrl" you can read it and call the "TransactionServices.getTransactionAdvSearchResults()" method.

Hide Approve/Reject Buttons in Fiori Master Details Page

I am looking to hide the Approve/Reject Buttons in the Details Page of a Fiori App based on certain filter conditions. The filters are added in the Master List view (Left hand side view) thru the view/controller extension.
Now, if the user selects certain type of filter ( Lets say, Past Orders) - then the approve/reject button should not be displayed in the Order Details Page.
This is how I have defined the buttons in the Header/Details view
this.oHeaderFooterOptions = {
oPositiveAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_APPROVE"),
id :"btn_approve",
onBtnPressed: jQuery.proxy(that.handleApprove, that)
},
oNegativeAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_REJECT"),
id :"btn_reject",
onBtnPressed: jQuery.proxy(that.handleReject, that)
},
However at runtime, these buttons are not assigned the IDs I mentioned, instead they are created with IDs of __button0 and __button1.
Is there a way to hide these buttons from the Master List View?
Thank you.
Recommended:
SAP Fiori design principles only talk about disabling the Footer Buttons instead of changing the visibility of the Button.
Read More here about Guidelines
Based on filter conditions, you can disable like this:
this.setBtnEnabled("btn_approve", false);
to enable again: this.setBtnEnabled("btn_approve", true);
Similarly you can change Button text using this.setBtnText("btn_approve", "buttonText");
Other Way: As #TobiasOetzel said use
this.setHeaderFooterOptions(yourModifiedHeaderFooterOptions);
you can call setHeaderFooterOptions on your controller multiple times eg:
//Code inside of the controller
_myHeaderFooterOptions = {
oPositiveAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_APPROVE"),
id :"btn_approve",
onBtnPressed: jQuery.proxy(that.handleApprove, that)
},
oNegativeAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_REJECT"),
id :"btn_reject",
onBtnPressed: jQuery.proxy(that.handleReject, that)
}
},
//set the initial options
onInit: function () {
this.setHeaderFooterOptions(this._myHeaderFooterOptions);
},
//modify the options in an event
onFilter : function () {
//remove the negative action to hide it
this._myHeaderFooterOptions.oNegativeAction = undefined;
this.setHeaderFooterOptions(this._myHeaderFooterOptions);
},
//further code
so by manipulating the _myHeaderFooterOptions you can influence the displayed buttons.
First, you should use sId instead id when defining HeaderFooterOptions, you can get the footer buttons by sId, for example, the Approve button.
this._oControlStore.oButtonListHelper.mButtons["btn_approve"]
Please check the following code snippet:
S2.view.controller: You have a filter event handler defined following and use EventBus to publish event OrderTypeChanged to S3.view.controller.
onFilterChanged: function(oEvent) {
// Set the filter value, here i use hard code
var sFilter = "Past Orders";
sap.ui.getCore().getEventBus().publish("app", "OrderTypeChanged", {
filter: sFilter
});
}
S3.view.controller: Subscribe event OrderTypeChanged from S2.view.controller.
onInit: function() {
///
var bus = sap.ui.getCore().getEventBus();
bus.subscribe("app", "OrderTypeChanged", this.handleOrderTypeChanged, this);
},
getHeaderFooterOptions: function() {
var oOptions = {
oPositiveAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_APPROVE"),
sId: "btn_approve",
onBtnPressed: jQuery.proxy(that.handleApprove, that)
},
oNegativeAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_REJECT"),
sId: "btn_reject",
onBtnPressed: jQuery.proxy(that.handleReject, that)
}
};
return oOptions;
},
handleOrderTypeChanged: function(channelId, eventId, data) {
if (data && data.filter) {
var sFilter = data.filter;
if (sFilter == "Past Orders") {
this._oControlStore.oButtonListHelper.mButtons["btn_approve"].setVisible(false);
}
//set Approve/Reject button visible/invisible based on other values
//else if(sFilter == "Other Filter")
}
}

Meteor JS: What is the best way to store states for a specific template instance?

I'm learning about Session and reactive data sources in Meteor JS. They work great for setting global UI states. However, I can't figure out how to scope them to a specific instance of a template.
Here's what I'm trying to do
I have multiple contenteditable elements on a page. Below each is an "Edit" button. When the user clicks on the Edit button, it should focus on the element and also show "Save" and "Cancel" buttons.
If the user clicks "Cancel", then any changes are eliminated, and the template instance should rerender with the original content.
Here's the code I have so far
// Helper
Template.form.helpers({
editState: function() {
return Session.get("editState");
}
});
// Rendered
Template.form.rendered = function(e){
var $this = $(this.firstNode);
var formField = this.find('.form-field');
if (Session.get("editState")) formField.focus();
};
// Event map
Template.form.events({
'click .edit-btn' : function (e, template) {
e.preventDefault();
Session.set("editState", "is-editing");
},
'click .cancel-btn' : function (e, template) {
e.preventDefault();
Session.set("editState", null);
},
});
// Template
<template name="form">
<div class="{{editState}}">
<p class="form-field" contenteditable>
{{descriptionText}}
</p>
</div>
Edit
Save
Cancel
</template>
// CSS
.edit-btn
.cancel-btn,
.save-btn {
display: inline-block;
}
.cancel-btn,
.save-btn {
display: none;
}
.is-editing .cancel-btn,
.is-editing .save-btn {
display: inline-block;
}
The problem
If I have more than one instance of the Form template, then .form-field gets focused for each one, instead of just the one being edited. How do I make so that only the one being edited gets focused?
You can render a template with data, which is basically just an object passed to it when inserted in to a page.
The data could simply be the key to use in the Session for editState.
eg, render the template with Template.form({editStateKey:'editState-topForm'})
you could make a handlebars helper eg,
Handlebars.registerHelper('formWithOptions',
function(editStateKey){
return Template.form({editStateKey:editStateKey})
});
then insert it in your template with
{{{formWithOptions 'editState-topForm'}}} (note the triple {, })
Next, change references from Session.x('editState') to Session.x(this.editStateKey)/ Session.x(this.data.editStateKey)
Template.form.helpers({
editState: function() {
return Session.get(this.editStateKey);
}
});
// Rendered
Template.form.rendered = function(e){
var $this = $(this.firstNode);
var formField = this.find('.form-field');
if (Session.get(this.data.editStateKey)) formField.focus();
};
// Event map
Template.form.events({
'click .edit-btn' : function (e, template) {
e.preventDefault();
Session.set(this.editStateKey, "is-editing");
},
'click .cancel-btn' : function (e, template) {
e.preventDefault();
Session.set(this.editStateKey, null);
},
});
Note: if you are using iron-router it has additional api's for passing data to templates.
Note2: In meteor 1.0 there is supposed to be better support for writing your own widgets. Which should allow better control over this sort of thing.
As a matter of policy I avoid Session in almost all cases. I feel their global scope leads to bad habits and lack of good discipline regarding separation-of-concerns as your application grows. Also because of their global scope, Session can lead to trouble when rendering multiple instances of a template. For those reasons I feel other approaches are more scalable.
Alternative approaches
1 addClass/removeClass
Instead of setting a state then reacting to it elsewhere, can you perform the needed action directly. Here classes display and hide blocks as needed:
'click .js-edit-action': function(event, t) {
var $this = $(event.currentTarget),
container = $this.parents('.phenom-comment');
// open and focus
container.addClass('editing');
container.find('textarea').focus();
},
'click .js-confirm-delete-action': function(event, t) {
CardComments.remove(this._id);
},
2 ReactiveVar scoped to template instance
if (Meteor.isClient) {
Template.hello.created = function () {
// counter starts at 0
this.counter = new ReactiveVar(0);
};
Template.hello.helpers({
counter: function () {
return Template.instance().counter.get();
}
});
Template.hello.events({
'click button': function (event, template) {
// increment the counter when button is clicked
template.counter.set(template.counter.get() + 1);
}
});
}
http://meteorcapture.com/a-look-at-local-template-state/
3 Iron-Router's state variables
Get
Router.route('/posts/:_id', {name: 'post'});
PostController = RouteController.extend({
action: function () {
// set the reactive state variable "postId" with a value
// of the id from our url
this.state.set('postId', this.params._id);
this.render();
}
});
Set
Template.Post.helpers({
postId: function () {
var controller = Iron.controller();
// reactively return the value of postId
return controller.state.get('postId');
}
});
https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#setting-reactive-state-variables
4 Collection data
Another approach is to simply state by updating data in your collection. Sometimes this makes perfect sense.
5 update the data context
Session is often the worse choice in my opinion. Also I don't personally use #3 as I feel like being less tied to iron-router is better incase we ever want to switch to another router package such as "Flow".

Categories