Send $scope between controller and Module - angularjs

I've been stuck on a problem for 4 days. I use a plugin Autocomplete, a directive for AngularJS that uses a script in my html template.
I customized this to add a button that open a modal to add another city if autocomplete find nothing.
<ion-view title=""hide-nav-bar="true" hide-back-button="true" cache-view="false">
<script type="text/ng-template" id="/my-custom-template.html" >
<div class="angucomplete-holder" ng-class="{'angucomplete-dropdown-visible': showDropdown}">
<div class="angucomplete-row" ng-controller="ShareCtrl" ng-click="selectResult({title: searchStr, originalObject: { name: searchStr, custom: true }})" ng-mouseenter="hoverRow(results.length)" ng-class="{'angucomplete-selected-row': results.length == currentIndex}>
<div class="angucomplete-title" ng-click="openModal1()" ng-model="item.cat_id" style="text-align:center;"><i class="ion-plus-circled"></i> Ajouter un lieu</div>
</div>
</div>
</script>
<div class="item item-input" style="width:100%;overflow: visible;z-index:1000;">
<div angucomplete-alt id="members"
placeholder="Lieux"
pause="100"
selected-object="item.place"
remote-url="http://api.formcy.com/v1/search_place?search="
remote-url-data-field="data"
title-field="name"
initial-value="{{nomlieux}}"
template-url="/my-custom-template.html"
style="width:95%;"
/></div>
</div>
<label class="item item-input">
<textarea ngMaxlength="180" placeholder="Que vais-je faire cette semaine ?" ng-model="item.title" rows="3"></textarea>
</label>
<ion-toggle toggle-class="toggle-calm" ng-model="item.private" ng-true-value="1" ng-false-value="0">Name </ion-toggle>
</ion-view>
I use a ng-controller to open my modal and add another city but it does not return the scope updated on my controller ShareCtrl.
However, the function openModal1() is in this controller and work perfectly..
My controller
$scope.add = function(){
.....code.....
request.success(function(data, status, headers, config) {
$scope.status = "Votre lieux a été ajouté !";
$scope.item.place_id = data.place_id;
console.log($scope.item);
$scope.modalCtrl1.hide();
});
};
How I can force the $scope.item update without using a service?

If you want to avoid services, you could use events : $rootScope.$broadcast (or $emit) and $scope.$on.

Related

$broadcast is not working in Angularjs

I am using two controllers. When changes happen in one controllers it should get changed immediately in the other controller. I am using the $broadcast event to achive this.
My code:
My First controller
app.controller('configurationCtrl', function($scope, $http,Notification,$rootScope,$cookies) {
$scope.awssubmit=function(){
$scope.page_loader=true
$http.post("/insert_config_details",$scope.userdata).then(function(List){
if(List){
$scope.page_loader=false;
$cookies.put("bucket",$scope.userdata.bucket_name)
$scope.$broadcast('eventEmitedName', 'Some data');
Notification.success('<span class="glyphicon glyphicon-ok"></span> <strong>AWS Configuration details updated successfully.</strong>');
}
else{
$scope.page_loader=false;
Notification.error('<span class="glyphicon glyphicon-ok"></span> <strong>Error!!! Please try again later.</strong>');
}
$scope.awssave = false;
$scope.awstext=true;
})
}
});
My Second Controller:
app.controller('SidemenuController', function($scope, $http,$location,BucketService)
{
$scope.$on('eventEmitedName', function (event, data) {
console.log("Called"); //I am not getting this
value
console.log(data); // 'Some data' // I am not getting this
value
});
});
aws_submit() is called from my view and everything seems to work fine. But in SidemenuController I am not getting any data. Is there any mistake in my code?
Update:
My view :
<form id="awsform" method="post" name="awsform" class="form-horizontal" novalidate>
<div class="col-sm-6 four_module_config">
<div class="account_settings">
<div class="col-sm-12 heading_config" ng-hide="awssave">
<h4 class="sub_title col-sm-11" style="border-bottom:none">AWS S3 Configurations</h4>
<% if(valid_role[1]) { %>
<div class="action col-sm-1">
<span class="actico editrole" ng-click="editaws()">
<a href='javascript:void(0)' ></a>
</span>
</div>
<% } %>
</div>
<div class="col-sm-12 heading_config" ng-show="awssave">
<h4 class="sub_title col-sm-9" style="border-bottom:none">AWS S3 Configurations</h4>
<div class="action col-sm-3 close_config">
<button type="button" class="site_btn submit_btn save_config col-sm-2" id="submit" ng-show="awstest"
ng-click="verifyaws()">Test</button>
<button type="button" class="site_btn submit_btn save_config col-sm-2" id="submit" ng-show="submitawssave"
ng-click="awssubmit()">Submit</button>
<button type="button" class="site_btn submit_btn save_config col-sm-2" id="submit" ng-click="closeaws()">Cancel</button>
</div>
</div>
<div class="ipfield col-md-8 hint_txt_conf">
*Enter your AWS access Key, S3 Bucket name configured in your AWS Environment. Which is used to store your document in the
cloud.
</div>
<div class="ipfield first_ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS access key <span class="mandat">*</span></label>
<input type="password" ng-disabled="awstext" ng-model="userdata.key" required name="key" class="txt_box" id="key" placeholder="Enter AWS access key">
<span toggle="#key" class="fa fa-fw fa-eye field_icon toggle-password"></span>
</div>
</div>
<div class="ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS Secret Key <span class="mandat">*</span></label>
<input type="password" ng-disabled="awstext" ng-model="userdata.secretkey" required name="secretkey" class="txt_box" id="secretkey" placeholder="Enter AWS Secret Key">
<span toggle="#secretkey" class="fa fa-fw fa-eye field_icon toggle-password"></span>
</div>
</div>
<div class="ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS Region Code <span class="mandat">*</span></label>
<input type="text" ng-disabled="awstext" ng-model="userdata.region" required name="region" class="txt_box" id="region" placeholder="Enter AWS Region Code">
</div>
</div>
<div class="ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS Bucket Name <span class="mandat">*</span></label>
<input type="text" ng-disabled="awstext" ng-model="userdata.bucket_name" required name="bucket_name" class="txt_box" id="bucket"
placeholder="Enter AWS Bucket Name">
</div>
</div>
</div>
</div>
</form>
If you want to send data from one controller to another controller using $brodcast than use $rootscope.$broadcast
$rootScope.$broadcast('eventEmitedName', 'Some data');
Second Controller
app.controller('SidemenuController', function($scope, $http,$location,BucketService) {
$scope.$on('eventEmitedName', function (event, data) {
console.log("Called");
console.log(data); // 'Some data'
$scope.bucket = data;
});
});
Note: Do not use $rootscope.$on as listener because $rootscope
listener are not destroyed . Instead it will create listeners stack
If you want to call one controller event into another there are four methods available:
$rootScope.$broadcast() if your controller are not in a parent / child relation.
If your second controller (event fired here) is a parent you can use $scope.$broadcast();
If your second controller (event fired here) is a child you can use $scope.$emit();
The best way to solve this would be to use a service -> Example of using a service to share data between controllers.
Note: You need to destroy $rootScope.$on() listeners manually avoid stacking events. This Difference between $rootScope.$on vs $scope.$on and this Do you need to unbind $scope.$on in $scope $destroy event? will help you understand the basics of using events.
View
<div ng-controller="MyCtrl">
<button ng-click="broadcast()">
broadcast
</button>
</div>
<div ng-controller="MySecondCtrl">
{{ test }}
</div>
AngularJS application
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope, $rootScope) {
$scope.broadcast = function() {
$rootScope.$broadcast('test', 'testit');
}
});
myApp.controller('MySecondCtrl', function($scope, $rootScope) {
var registerScope = $rootScope.$on('test', function(test, args) {
console.log(args);
$scope.test = args;
});
// clean up, destroy event when controller get destroyed.
$scope.$on('$destroy', registerScope);
});
> demo fiddle

Angular Wiring up two controllers from Model to auto fill form

I've got an angular app I'm working on where I'm trying to auto fill a pop up modal based on a user's selection.
I thought I could use my model service to keep track of what the user selected and 'wire' the controller for the <select> list and it's edit button to the model but that doesn't seem to work.
Adding to the complexity I'm using angular-route and my <select> list is buried in a view. I was trying to keep my pop up modals in a separate controller outside the view because they've got their own templates and I had problems when I nested them into the view...
I've seen a few examples of wiring up angular apps and thought I understood them but I can't figure out what I'm doing wrong.
EDIT (thanks Pankaj Parkar for pointed out my mistakes in the plunker):
I have a plunker here:
https://plnkr.co/edit/6f9FZmV8Ul6LZDm9rcg9?p=preview
Below is the snipped in a single HTML page with CDN links :).
Am I just completely misunderstanding how angularjs is suppose to work?
<html ng-app="myApp">
<head>
<title>Bootstrap 3</title>
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<div ng-view></div>
<script id="editables.html" type="text/ng-template">
<div class="container">
<div class="jumbotron">
<form>
<div class="form-group">
<select class="form-control" id="mapsSelect" size="10" multiple ng-model="model.selected">
<option ng-repeat="n in editables">{{n}}</option>
<select>
</div>
<a href="#editModal" class = "btn btn-info" data-toggle="modal" ng-click="edit()" >Edit</a>
</form>
</div>
</div><!--end container div-->
</script>
<div ng-controller="modalsController">
<div id="editModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4>New Map</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="name" class="col-lg-3 control-label">Name</label>
<div class="col-lg-9">
<input type="text" class="form-control" id="name" ng-model="formModel.name"></input>
</div>
</div>
<div class="form-group">
<label for="desc" class="col-lg-3 control-label">Description</label>
<div class="col-lg-9">
<input type="text" class="form-control" id="desc" ng-model="formModel.desc"></input>
</div>
</div>
<div class="modal-footer">
<pre> {{ formModel | json }}<br><br>Working: {{ workingMap }}</pre>
Cancel
Continue
</div>
</form>
</div>
</div>
</div><!-- end modal -->
</div>
</body>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-route.min.js"></script>
<script src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- <script src = "js/script.js"></script> -->
<script>
var app = angular.module('myApp', ['ngRoute']);
var modelService = function ($log){
var moduleHello = function(myMessage){
console.log("Module hellow from myService " + myMessage);
}
var moduleNames = {
"First" : {desc: "First's Description"},
"Second" : {desc: "Second's Description"},
"Third" : {desc: "Third's Description"}
};
var moduleWorkingName = {};
return {
hello: moduleHello,
editables: moduleNames,
workingName: moduleWorkingName
}
}//end modelService
app.factory("modelService", ["$log", modelService]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/editables', {
controller: "editablesController",
templateUrl: "editables.html"
}).
otherwise({
redirectTo: "/editables"
});
}]);
app.controller('editablesController', ['$scope', '$log','modelService', function($scope,$log, $modelService) {
$scope.model = {};
//console.log( JSON.stringify( $modelService.editables ) );
$scope.editables = [];
for ( name in $modelService.editables){
$scope.editables.push( name );
}
$scope.edit = function(){
if ( typeof $modelService.editables [$scope.model.selected] != 'undefined'){
$modelService.workingName = $modelService.editables [$scope.model.selected];
console.log ("Setting my working name to " + JSON.stringify( $modelService.workingName ) );
}else{
console.log ("Nothing Selected");
}
}
}]);
app.controller('modalsController', ['$scope','modelService', function($scope,$modelService) {
$scope.formModel = {};
$scope.formModel.name = "Hard coding works of course";
$scope.formModel.desc = $modelService.workingName.desc; //But I can't seem to get this to update. I thought pointing it at an object in the Model would be enough.
console.log("Firing up modalsController");
}]);
</script>
</html>
I spent the last two days mulling over this in my head and I think I figured it out. For starters, here's the (working) plunker:
https://plnkr.co/edit/Kt3rebPtvGTt0WMXkQW4?p=preview
Now, the explanation. I was trying to keep a separate 'formModel' object that kept track of the controller's state. But that's both silly and pointless.
Instead what you're supposed to do is:
a. Create an object in your service to hold all your data (I just called this 'model')
b. For each controller that needs to share data create a variable on the $scope of the controller and point it to your 'model' variable from your service.
c. after that use the variables from your model in your html.
So in both my controllers you'll find this line:
$scope.model = $modelService.model;
and in my HTML you'll find stuff like this:
<input type="text" class="form-control" id="name" ng-model="model.workingName.name"></input>
notice how I'm using "model.workingName.name"? This references $scope.model.workingName.name, which thanks to the line $scope.model = $modelService.model from my JavaScript now points directly to my model.
And that is how you "wire up" Angular.
By the way, experienced Angular folks have probably noticed that this part:
$scope.editables = [];
for ( name in $modelService.model.names){
$scope.editables.push( name );
}
probably belongs in a directive instead of a controller because I'm editing the DOM.
Stuff like that's what makes it so hard to learn AngularJS. There's so many concepts to get the hang of.

Add/Remove class if checkbox is checked/unchecked (AngularJS)

I need to toggle a class if a checkbox is checked/unchecked with AngularJS. My Code is working on Plunker but in my controller there is no functionality.
Here is the Plunker: Click!
My Controller looks like this:
angular.module('inspinia')
.controller('MainController', function ($location, $scope, $state) {
// initialize iCheck
angular.element('.i-checks').iCheck({
checkboxClass: 'icheckbox_square-green',
radioClass: 'iradio_square-green'
});
//Checkbox functionality
$scope.isChecked = function() {
if ($scope.checked) {
return false;
}else{
return true;
}
};
});
HTML
<div class="panel panel-default confirm-panel accept-terminplanung">
<div class="panel-body text-muted ibox-heading">
<form action="#" method="post" role="form">
<div class="i-checks" iCheck>
<label class="">
<div class="icheckbox_square-green">
<input type="checkbox" class="i-checks" ng-model="checked">
</div>
<p class="no-margins">Hiermit akzeptiere ich die Bedingungen des geschlossenen Dozentenvertrages und nehme den Bildungsauftrag für die ausgewählten Ausbildungen verbindlich an.</p>
</label>
</div>
<button type="button" name="termin-bestaetigen" class="btn btn-w-m btn-warning submit-appointment disabled" ng-class="{disabled: isChecked()}">Terminplanung übernehmen</button>
</form>
</div>
</div>
What am I doing wrong?
As I can understand from the provided piece of code iCheck is something that is not working in angular scope, like JQuery. So every time your value inside this component changes you need to trigger a $digest cycle with a use of $scope.$digest() or $scope.$apply().
In iCheck documentation you can find callbacks section, so you can subscribe to that event and do $scope.$apply() in it.
For example, inside your controller:
<your-iCheck-element>.on('ifChecked', function(event){
$scope.$apply();
});
Your function is basically doing nothing, but giving back the opposite value of checked. You can simply use negation of your model.
ng-class="{disabled: !checked}"

localStorage AngularJS does not save anything

I want to create a text area where if i add some text and click on save, the text should be saved in localStorage. So if i open the text area again, i can see it still there.
HTML
<ion-view view-title="CWIN 2016 - Votre avis">
<ion-content>
<div class="list card user-infos-card">
<div class="item aw-dark-blue"> <h2 class="activity-name"></h2> Notes</div>
<textarea ng-model="note" rows="20" cols="50"></textarea>
<div class="item tabs tabs-secondary tabs-icon-left aw-dark-blue" ng-click="saveNote()" ng-model="note">Enregistrer vos notes</div>
<div ng-show="error">
<p class="form-error-message">Veuillez saisir des notes</p>
</div>
</div>
</ion-content>
</ion-view>
JS
angular.module('companion.noteBookController', ['LocalStorageModule'])
.controller('noteBookController', function ($scope, localStorageService){
$scope.note=localStorageService.get('note');
$scope.saveNote=function() {
localStorageService.set('note', $scope.note);
}
});
I don't underdstand the problem. Besides I don't have any errors.
Change this line
<div class="item tabs tabs-secondary tabs-icon-left aw-dark-blue" ng-click="saveNote(note)">Enregistrer vos notes</div>
and in js
angular.module('companion.noteBookController', ['$localStorage'])
.controller('noteBookController', function ($scope, $localStorage){
$scope.saveNote=function(note_val) {
console.log(note_val);
$localStorage.note = note_val;
}
});
if you want to get value then you can use this
var my_note = $localStorage.note;

$http.get not executing functions on success

I am doing my first Angular project (ionic framework) where i have to get some data from database and on success I havet to
store it in a variable
navigate to a page where this variable is used.
The page is navigating, but data are not sent.
Here is my search.html code:
<body ng-app="starter" ng-controller="ListCtrl">
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Real Estate</h1>
</ion-header-bar>
<ion-content>
<h4 align="center"> Enter Place or Pincode </h4>
<div class="list list-inset" >
<label class="item item-input">
<input type="text" name="place" ng-model="data.place" value="" placeholder="Place" ng-focus="$scope.placefocus=true;data.pincode=null" ng-blur="$scope.placefocus=false" ng-disabled = "$scope.pincodefocus">
</label>
<label class="item item-input">
<input type="number" name="pincode" ng-model="data.pincode" value="" placeholder="Pin Code" ng-focus="$scope.pincodefocus=true;data.place=null" ng-blur="$scope.pincodefocus=false" ng-disabled="$scope.placefocus">
</label>
</div>
<button class="button button-block button-positive" ng-click="getdata()">
Search
</button>
</ion-content>
</ion-pane>
</body>
And here is my controller code :
app.controller('ListCtrl',function($scope,$http,$location,$window){
$scope.data = {};
$scope.getdata = function(){
//alert($scope.data.place);
$http.get("http://localhost/angular/data.php")
//,{'place':$scope.data.place,'pincode':$scope.data.pincode})
.success(function(response,status,headers,config){
alert(response);
$scope.datas=response;
$scope.navig('/show.html');
})
}
$scope.navig = function(url){
$window.location.href=url;
};
});
and here is my show.html page :
<ion-content>
<div class="list card" ng-repeat="site in datas">
<div class="item item-body">
<a href="#" class="subdued"><img class="full-image" src="img/{{site.image}}" height="150px">
<p>
RS.{{site.price}} &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp <span> {{site.square_feet}} sq.ft &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp</span><span>{{site.bed}} BHK</span>
</p>
</a>
</div>
</div>
</ion-content>
alert(response) in the controller code alerts [object Object],[object Object],[object Object]
But the output page (show.html) is blank
If I call navig("/show.html") directly from the button click (in search.html) instead of getdata() and change the controller code to the below one, I am getting the result: (But I cannot execute this way because I have to get data from database for particular place and pincode entered)
app.controller('ListCtrl',function($scope,$http,$location,$window){
$scope.data = {};
$http.get("http://localhost/angular/data.php")
//,{'place':$scope.data.place,'pincode':$scope.data.pincode})
.success(function(response,status,headers,config){
alert(response);
$scope.datas=response;
})
$scope.navig = function(url){
$window.location.href=url;
};
});
Don't use the success function, use the .then() function.The code below is from the angular documentation.
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Here is the text from the Documentation
Deprecation Notice
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
$scope works with in controller only! Instead of $scope use $rootScope.
It might be the promise.
Why don't you try this.
app.controller('ListCtrl',function($scope,$http,$location,$window){
$scope.data = {};
$http.get("http://localhost/angular/data.php")
//,{'place':$scope.data.place,'pincode':$scope.data.pincode})
.then(function(response){
alert(response);
$scope.datas=response;
})
$scope.navig = function(url){
$window.location.href=url;
};
});

Resources