how to call parent function controller from directive react component angularjs + reactjs? - angularjs

I have angular application and we start using react as render data.we have one problem is how can we call $scope.showUserDetails from directive react component
.I tried using this.props.scope.$parent.showUserDetails(); I have Uncaught TypeError: Cannot read property '$parent' of undefined
react component
/** #jsx React.DOM */
var MYCOMPONENT = React.createClass({
displayName: 'MYCOMPONENT',
handleClick: function (e) {
console.log('You clicked');
this.props.scope.$parent.showUserDetails();
},
render: function (){
var listUser = this.props.data.map(function(item){
return(
React.DOM.div(
{
className: 'panel panel-default staff-reception ' + item.statusType.toLocaleLowerCase() + 'Office',
'ng-click': 'showUserDetails(' + item + ')',
onClick: this.handleClick
},
React.DOM.div(
{
className: 'panel-body'
},
React.DOM.span(null, item.firstName + ' ' + item.lastName + ' ' + item.directDial + ' Ext:' + item.voiceMailExt)
)
)
);
},this);
return (React.DOM.div({className:'col-xs-12 col-md-6 col-lg-4'}, listUser));
}
});
controller
(function () {
'use strict';
var app = angular.module('app');
var ReceptionReactController = function ($scope, ReceptionReactService, $modal) {
$scope.showUserDetails = function (user, index) {
var modalInstance = $modal.open({
templateUrl: 'UserDetails.html',
controller: UserDetailsController,
size: 'lg',
resolve: {
user: function () {
return user;
}
}
});
modalInstance.result.then(function (userUpdatedStatus) {
updateUserStatus(userUpdatedStatus);
}, function () {
});
};
};
app.controller('ReceptionReactController', ['$scope', 'ReceptionReactService', '$modal', '$window', ReceptionReactController]).directive('fastNg', function () {
return {
restrict: 'E',
scope: {
data: '='
},
link: function (scope, el, attrs){
scope.$watch('data', function(newValue, oldValue){
React.render(React.createElement(
MYCOMPONENT, {
data: newValue
}),
el[0]
);
});
}
}
});
}());
view
<fast-ng data="ListTitleUsers.users"></fast-ng>

It seems like you should pass the function you want through the directive's attributes and into the react component's props. Something like this might work:
<fast-ng data="ListTitleUsers.users" show="showUserDetails"></fast-ng>
-
app.controller('ReceptionReactController', ['$scope', 'ReceptionReactService', '$modal', '$window', ReceptionReactController]).directive('fastNg', function () {
return {
restrict: 'E',
scope: {
data: '=',
show: '='
},
link: function (scope, el, attrs){
scope.$watch('data', function(newValue, oldValue){
React.render(React.createElement(
MYCOMPONENT, {
data: newValue,
show: scope.show
}),
el[0]
);
});
}
}
});
-
handleClick: function (e) {
console.log('You clicked');
this.props.show();
},
-
onClick: this.handleClick.bind(this, item)

Related

I have a angular directive for kendo grid. My issue is ajax in my service fires only after the complete directive executes

My ajax fires after the complete directive executes. Is there any work around for this so that I can have my grid configuration loads before coming to the grid directive
gridApp.directive('grid', function () {
return {
restrict: "EA",
scope: {
gridName: "#"
},
template: '<h1>kendoDirective</h1><br/><div kendo-grid={{gridName}} options="gridOptions"></div>',
controller: function ($scope, $element, $attrs, widgetUtils) {
var gridConfig = widgetUtils.GetGridOption().then(onLoad);
var onLoad = function (data) {
$scope.gridOptions = data;
}
console.log('DirectiveScope: ' + $scope.gridOptions);
},
link: function ($scope, $element, $attrs) {
}
};
});
gridApp.service('widgetUtils', function ($http) {
var getGridOption = function () {
return $http.get('/Base/LoadGridConfiguration').then(function (response) {
return response.data;
});
}
return {
GetGridOption: getGridOption
};
});
You can handle it with ng-if in template. I created $scope.isReady and change it state after options loaded.
gridApp.directive('grid', function () {
return {
restrict: "EA",
scope: {
gridName: "#"
},
template: '<h1>kendoDirective</h1><br/><div data-ng-if="isReady" kendo-grid={{gridName}} options="gridOptions"></div>',
controller: function ($scope, $element, $attrs, widgetUtils) {
var gridConfig = widgetUtils.GetGridOption().then(onLoad);
$scope.isReady = false;
var onLoad = function (data) {
$scope.gridOptions = data;
$scope.isReady = true; // here we ready to init kendo component
$scope.$apply();
}
console.log('DirectiveScope: ' + $scope.gridOptions);
},
link: function ($scope, $element, $attrs) {
}
};
});

Unit Testing a watch method call in Directive link function

I have the following Directive
.directive("myContainer", function (myContainerService,$window) {
return {
restrict: 'A',
templateUrl: "myContainer/MyContainer.tpl.html",
controller: 'myCtrl',
controllerAs: 'myCtrl',
scope: {
items: '='
},
link: function (scope, element) {
var timeout;
scope.$watch('myCtrl.items', function (items) {
var windowWidth = $window.innerWidth - 65;
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
myContainerService.saveItems(items);
}, 1000);
}, true);
}
};
})
And here is the Unit Test i have.
describe("myCtrl", function(){
var myCtrl;
var dirEle ;
var myScope;
// var to store the Mock Items
var myContainerService = $injector.get('myContainerService');
var items = [..]
beforeEach(inject(function($compile, $httpBackend){
$httpBackend.whenGET(/.*my-app\/restful-services\/items*./).respond({...});
scope.items = myContainerService.getItems();
dirEle = $compile('<div my-container items="items"></div>')(scope);
scope.$digest();
myScope = dirEle.isolateScope();
myCtrl = myScope.myCtrl;
}));
fit("Saving Items", inject(function($timeout){
spyOn(myContainerService, 'saveItems');
//$timeout.flush();
myScope.$digest();
$timeout.flush();
expect(myContainerService.saveItems).toHaveBeenCalledWith(myCtrl.items);
}));
});
And my test is failing as the saveItems is not getting called at all. Not sure what i am doing wrong.
Appreciate any inputs.
Thanks
You need to be using angulars $timeout that way in your test your $timeout.flush() will work:
.directive("myContainer", function (myContainerService,$window, $timeout) {
return {
restrict: 'A',
templateUrl: "myContainer/MyContainer.tpl.html",
controller: 'myCtrl',
controllerAs: 'myCtrl',
scope: {
items: '='
},
link: function (scope, element) {
var timeout;
scope.$watch('myCtrl.items', function (items) {
var windowWidth = $window.innerWidth - 65;
$timeout.cancel(timeout);
timeout = $timeout(function () {
myContainerService.saveItems(items);
}, 1000);
}, true);
}
};
})

$scope.$watch not detecting changes in directive in same module

I'm implementing a watch in the controller, when user toggles a button. I have a watch inside the directive and that is working, e.g. it detects that the scope variable has changes but if I have a watch inside the controller it does not detects
<button toggle-button active-text="Yes" inactive-text="No" ng-model="light.state">Show millions</button><br>
here is the code:
'use strict';
angular.module('fiveYearOverview', ['fiveYearOverviewServices', 'fiveYearOverviewDirectives'])
.controller('fiveYearCtrl', [
'$scope', 'reports',
function ($scope, reports) {
//not working
$scope.$watch('lightState', function (newValue, oldValue) {
if (newValue)
console.log("I see a data change!");
}, true);
}
])
.directive('toggleButton', function () {
return {
require: 'ngModel',
scope: {
activeText: '#activeText',
inactiveText: '#inactiveText',
lightState: '=ngModel'
},
replace: true,
transclude: true,
template: '<div>' +
'<span ng-transclude></span> ' +
'<button class="btn" ng-class="{\'btn-primary\': state.value}" ng-click="state.toggle()">{{activeText}}</button>' +
'<button class="btn" ng-class="{\'btn-primary\': !state.value}" ng-click="state.toggle()">{{inactiveText}}</button>' +
'</div>',
link: function postLink(scope) {
scope.lightState = scope.inactiveText;
scope.state = {
value: false,
toggle: function () {
this.value = !this.value;
scope.lightState = this.value ? scope.activeText : scope.inactiveText;
console.log(scope.lightState);
//working
scope.$watch('lightState', function (newValue, oldValue) {
if (newValue)
console.log("I see a data change!");
}, true);
}
};
}
}
});
What is that i'm doing wrong ?
By defining a scope in the directive you are creating an isolated scope for it. Thats why you cant access its members from the controller.
lightState is being declared in a scope below that of fiveYearCtrl making it inaccessible as outlined here.
An alternative solution could be to define the callback function in fiveYearCtrl and call it from the directive.
.controller('fiveYearCtrl', [
'$scope', 'reports',
function ($scope, reports) {
this.consoleLog = function (newValue, oldValue) {
if (angular.isDefined(newValue))
console.log("I see a data change!");
};
}
])
link: function postLink(scope, element, attrs, ctrl)
{
scope.lightState = scope.inactiveText;
scope.state = {
value: false,
toggle: function () {
this.value = !this.value;
scope.lightState = this.value ? scope.activeText : scope.inactiveText;
console.log(scope.lightState);
//working
scope.$watch('lightState', ctrl.consoleLog, true);
}
};
}

How to make function to be fired when directive loaded?

I define this directive:
(function () {
"use strict";
angular.module("inspectionReview").directive("inspectionsReviewsList", ["config",inspectionsReviewsList]);
function inspectionsReviewsList(config) {
var directive = {
restrict: "E",
scope: {
objectId: "=",
region: "="
},
templateUrl: config.baseUrl + "app/InspectionReview/templates/inspectionsReviewsList.templ.html",
controller: "inspectionsReviewsListController",
controllerAs: "list"
}
return directive;
}
angular.module("inspectionReview").controller("inspectionsReviewsListController", ["$scope",
"$uibModal",
"inspectionReviewServices",
"toaster",
inspectionsReviewsListController]);
function inspectionsReviewsListController($scope, $uibModal, inspectionReviewServices, toaster) {
//===============================check status of site object================================
$scope.$watch('inspectionReviews', function () {
_.each($scope.inspectionReviews, function (value, key) {
if (!value.IsNormal) {
return $scope.status = false;
}
$scope.status = true;
})
}, true)
//===================================modal window============================================
$scope.open = function (size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'app/siteObjects/templates/myModalContent.tmpl.html',
controller: 'myModalWindowController',
size: 'sm',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
//$log.info('Modal dismissed at: ' + new Date());
});
};
}
})();
In the view:
<inspections-reviews-list id="object.Id"></inspections-reviews-list>
How can I make this function:
inspectionReviewServices.getValues(objectId).then(function (result) {
$scope.inspectionReviews = result.data;
});
to be fired when when directive is loaded.
You can assign a function to the directive's link property, as follows:
link : getValues;
The getValues functions is like this:
function getValues(scope, element, attributes) {
inspectionReviewServices.getValues(attributes.id).then(function (result) {
scope.inspectionReviews = result.data;
});
}
use like this... it will work..
function () {
angular.module("inspectionReview").directive("inspectionsReviewsList", ["config",inspectionsReviewsList]);
function inspectionsReviewsList(config) {
var directive = {
restrict: "E",
scope: {
objectId: "=",
region: "="
},
link : function getValues(scope, element, attributes) {
inspectionReviewServices.getValues(attributes.id).then(function (result) {
scope.inspectionReviews = result.data;
});
},
templateUrl: config.baseUrl + "app/InspectionReview/templates/inspectionsReviewsList.templ.html",
controller: "inspectionsReviewsListController",
controllerAs: "list"
}
return directive;
}

Angular popup with dynamic template and controller

I have found the following code that produces a popup window.
angular.module('plunker', ['ui.bootstrap', 'myModal']);
angular.module("myModal", []).directive("myModal", function ($modal, $timeout) {
"use strict";
return {
template: '<div ng-click="clickMe(rowData)" ng-transclude></div>',
replace: true,
transclude: true,
scope: {
rowData: '&myModal'
},
link: function (scope, element, attrs) {
scope.clickMe = function () {
$modal.open({
template: "<div>Created By:" + scope.rowData().data + "</div>"
+ "<div class=\"modal-footer\">"
+ "<button class=\"btn btn-primary\" ng-click=\"ok()\">OK</button>"
+ "<button class=\"btn btn-warning\" ng-click=\"cancel()\">Cancel</button>"
+ "</div>",
controller: function ($scope, $modalInstance) {
$scope.ok = function () {
$modalInstance.close({ test: "test"});
};
$scope.cancel = function () {
};
$timeout(function () {
$(".modal-dialog").draggable();
var resizeOpts = {
handles: "all", autoHide: true
};
$(".modal-dialog").resizable(resizeOpts);
}, 0);
},
backdrop: "static"
});
}
}
};
});
I would like to make this code generic and assign templates and their controllers on the fly. I guess I could specify a template with controller built-in but want to avoid doing that.
Thanks

Resources