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
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) {
}
};
});
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);
}
};
})
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);
}
};
}
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;
}
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