Ionic Directive elements not invoking functions (binding) on changes - javascript

I started my project using the Ionic Side Menu Starter.
I'm trying to get a Rating directive/control to work, from here:
https://github.com/fraserxu/ionic-rating
The module is loaded, and the template objects (the stars) render OK. Binding -from- my model/scope works one-time. But, clicking on the stars does nothing.
Some of the js does get invoked: ng-mouseleave="reset()" is hooked up to the parent element and does get invoked. But ng-click="rate($index + 1)" is attached to the that contains the star, and does not (I set breakpoints).
I suspect it may have something to do with the child scopes that are created based on the starter, but don't know.
<rating ng-model="review.rating" max="5"></rating>
And my controller:
angular.module('myapp.controllers').controller('NewReviewCtrl', function($scope, $stateParams) {
$scope.review = {};
$scope.review.rating = 3;
});
The module is loaded in a separate file:
angular.module('myapp.controllers', ['ionic.rating']).controller('AppCtrl', function($scope, $ionicModal, $timeout) {
...

Dayan's comment nailed it. I had the rating directive inside a label:
My Label
It works fine after removing it from inside the label.

Related

AngularJS MVC Razor - How does one define a single controller in multiple files?

I have an MVC application that has a master layout that has a #RenderBody() inside of it that renders the body of the individual page. In the master layout I have given the body tag an angularjs app name and controller name.
I want the controller to be defined in a separate global angular.js file. This will share common functions that every page can take advantage of.
myApp.controller('myController', ['$scope', '$http', function ($scope, $http) {
$scope.sharedFunction = //...shared function stuff
})';
I also want to add specific scope functions and variables in the child pages in MVC. When I get to the child pages, I believe I end up redefining the controller if I use the same syntax.
myApp.controller('myController', ['$scope', '$http', function ($scope, $http) {
$scope.showOverlay = false;
}]);
How can I make it so the same controller that is defined in the body gets page specific items added to it in the child pages that are rendered using #RenderBody()?
You need to define your 'app' as a module in Angular, like so:
var app = angular.module("app", [myController])
The 2nd part of the declaration allows you to pass in an array of 'dependencies' that your Angular app relies on. In this case, your app will include your 'myController' controller
Then use this attribute on the part of your html that you want Angular to act upon:
ng-app="app"
Doing this will make your controller available to any page that utilises your 'app' module.
I got this to work by nesting ng-controllers. The second controller inherited all of the first controller functions and I was able to overwrite them and add to them in the second controller.

Converting jQuery Modal Service to AngularJS directive doesn't allow 2 way binding

I've inherited another legacy system that a previous colleague was working on, he was asked to remove server side components from an app and replace them with AngularJS... it's an old JSP system and everything is a bit of a hack. Anyway, there is a jQuery library within the old system that produces Modal Windows, rather than have to add UI-Bootstrap my colleague converted this jQuery service to an AngularJS directive and it kind of works... but with one exception, here is the directive code...
.directive('popupWindow', ['$document', '$compile', function ($document, $compile, MessagesService) {
"use strict";
return {
restrict: 'A',
scope: {},
link: function (scope, element, attrs) {
var newPopup = new Basebox({
contentUrl: '/ng/xtemplate/widgets/CCC/' + scope.getType + '.html',
type: 'regular',
id: 'sf-basebox',
hideBackground: false,
overlay: true,
resolveTest: {getType: scope.getType, message: scope.message, config: scope.config }, // this is appended to the Modal Window as a ng-init and it renders correctly!
closeOnOverlay: false,
closeIcon: true,
checkOldIe: true,
afterContentLoad: function () {
$compile($document.find("#basebox"))(scope);
scope.$apply();
}
});
newPopup.create();
}
});
}
};
}]);
Now this works as it allows us to import HTML templates, it produces the Modal Window and allows us to set various properties, it also allows is to pass data objects (see the resolveTest property) to the controller of the model window. Everything works! Anything within the angularJS templating {{ }} is rendered and we can use angular directives such as ng-init, ng-repeat, etc, etc... however when trying to have two way binding between the view and the controller nothing seems to work, the data gets rendered from the controller to the view but not the other way around. The view never updates... here is the view and the controller
.controller('reportModelCtrl', function ($scope) {
$scope.val = {};
$scope.val.foo = 'blue';
})
Here is the view...
<div ng-controller="reportModelCtrl">
<input type="text" ng-model="val.foo"> {{ val.foo }} this is by default 'blue' but never updates
</div>
Like I say, I dynamically add an ng-init to the modal template and this works, but when I amend the text box nothing happens. Can anyone think of something I'm missing? Even if I try to update values using methods in the controller and ng-click in the view nothing is updated. Calling $scope.$apply() just results in an error. Do I need to add a form to my view? Sorry the jQuery Basebox library isn't included here but I just thought it would add to the confusion. I just really want suggestions or hints to getting the two way binding to work rather than a full answer.

Sharing $scope with cellTemplate using ui.grid

I'm using ui.grid to get a list of parts. I've created a column that contains a button which launches a modal. What I'm having trouble with is sharing the scope of the part that is contained in the row. I want to share the properties of that row with the the button that I'm creating using cellTemplate. I then want to share the $scope of the part row with the modal that it will launch.
I'm a bit stumped on how to actually do this.
So far I've tried
• Wrapping an ng-repeat around the button that I want to target. This kind of works but makes the app super slow
• Data-binding on the button via ng-class. I can't seem to target this correctly.
How can you share the $scope of an object that you're receiving via $http.get into the ui.grid with elements that you're creating with cellTemplate?
Disclaimer -- I always use controllerAs syntax, so if referencing the controller in the context of HTML is weird to you, just ignore that part and pretend like you setup the methods to be directly on the scope. I also do everything in Typescript, not Javascript, so I'm going to write the pertinent parts of the code in here. They should be easy to plug into your application.
The answer is a combination of the two answers you already have from Sunil and S.Baggy.
What you want to do is use the getExternalScopes() function and attach something to the scope of the HTML where your grid resides. The thing you handed the grid will take in the row and call your modal popup. See below for a little clarification.
Your HTML -
<div ng-controller="MyController as myController">
<div ui-grid="myController.GridObject" external-scopes="myController"></div>
</div>
By using controllerAs syntax and making the controller the reference in the external scopes, we can now gain access to everything in our controller. So we can call methods in it.. In order to do that, however, we have to use a cellTemplate, which it sounds like you already know how to do, and in that cellTemplate we have to have the following:
ng-click="getExternalScopes().methodToLaunchModal()"
Now the last part of hooking all this up is to write the methodToLaunchModal() method into the controller. For that we're borrowing the code from S.Baggy's answer. Here is a very abbreviated controller with the GridObject (the same one I referenced from the controller above):
app.controller('MainCtrl', function($scope, $modal) {
GridObject = {
... setup of all the other things
columnDefs: [{ etc, etc, }, { etc, cellTemplate: '<div ng-click="getExternalScopes().methodToLaunchModal(row.entity)">whatever</div>' }]
};
methodToLaunchModal: function(row) {
var modalInstance = $modal.open({
templateUrl: 'someTemplate',
controller: 'ModalController',
resolve: {
rowObject: function () { return row; }
}
});
};
});
At this point your modal scope will have an object named rowObject on it that will have all the properties from your row. So you should be able to call rowObject.SomeProperty to get its value.
Apologies if any of the syntax is slightly off.
I use the bootstrap $modal directive with code like this...
clickFunction: function (event, row) {
event.stopPropagation(); // prevents the current row from appearing as selected
var modalInstance = $modal.open({
templateUrl: 'views/modalcontent.tpl.html',
controller: 'ModalMessageController',
size: 'lg',
resolve: {
message: function () { return row.entity.serial_number; }
}
}
);
Then I just refer to {{message}} in the template. Of course you could pass in any other piece of data too.
You can access row and its properties on row selection or ng-click of that row using externalscopes
ng-click="getExternalScopes().onRowClick(row)"
onRowClick: function (row) {
row.entity.Property1; /// and so on for all row properties
}

Share selected select with another controller

I am trying to to share a selected option with another controller (And have it update when I select a new option). Something that would work like the 2-way data binding between controllers.
I've attempted this by setting up a factory like so
.factory("shareObjective", function($scope){
var shareObjective = {};
return {
shareObjective: shareObjective,
};
})
Then I inject this into the controller and bind it to the model of the select like so
$scope.selectModel = shareObjective.shareObjective;
I seem to be having some trouble getting this to work. I Basically just want to share the selected option (it's .name to be precise) with another controller and am struggling to do so. My first step was to get it to share into the factory to begin with, but I seem to be having no luck attempting this. Should I be using something like the $broadcast to keep the stream of information open? Thanks!
Edit - here's a plunkr http://plnkr.co/edit/L5lz4etQ7mUEhf9viNOk?p=preview
Yes, this won't work by default because you use two different scopes thus different ngModels.
Using a service also won't help because even if a click on a select with a ngModel in one scope will trigger a digest loop in that scope, it won't trigger it in the other scope.
As you suggest yourself you need to somehow notify the other scope to update itself, and yes you can do this through events ($broadcast and $on):
Both controllers contain
<select
ng-model="foo"
ng-options="foo for foo in foos"
></select>
And this is the JS:
var foos = [
'foo1',
'foo2',
'foo3'
];
function MyCtrl($scope, $rootScope) {
$scope.foo = foos[0];
$scope.foos = foos;
// detect broadcasts from other controllers and set our value to the one we received
$rootScope.$on('foo-event', function(e, data) {
$scope.foo = data;
});
// detect when foo changes and broadcast it's value
$scope.$watch('foo', function() {
$rootScope.$broadcast('foo-event', $scope.foo);
});
}
myApp.controller('MyCtrl1', ['$scope', '$rootScope', MyCtrl]);
myApp.controller('MyCtrl2', ['$scope', '$rootScope', MyCtrl]);
Here's the fiddle.
Notice that my code does not use a single controller, just a single controller implementation. You can write your own MyCtrl1 and Myctrl2 implementations that both have this code inside.
Also, while it would look like this generates an infinite loop between $watch and $on, it does not. $scope.foo = data; does not trigger $watch,

Angular not fetching data from factory

Hi i have the following plunker using a factory: plunker
When we click the button next to my academic programs, it gives a panel with the applied science and academic buttons. When we click on one of the buttons, it gives a list of some programs. When we click on one of those programs, it brings another panel which should contain the children of those programs.
I defined these children in a factory(services.js). But it is not bringing those elements from the json file. Where am i going wrong?
your path to your data.json (its currently data.js) file is wrong.
the json in the file is incorrect. You need to wrap all properies with ''.
Your path to bootstrap is wrong so its crashing on $().tooltip()
You had not even plugged up the service call. I added jsonService as a dependancy. JsonService as an injectable:
var app = angular.module('StudentProgram', ['ui.bootstrap', 'jsonService']);
app.controller('mycontroller', function(JsonService, $scope, $modal, $log) {
Then i added to your scope a call to get the data
JsonService.query(function(data){
$scope.degreecategories = data;
console.log(data);
});
Working plnkr . Please next time point more work into your question... you are lucky I am bored.

Categories

Resources