AngularJS Include Refresh - angularjs

I have a html page which I am including as follows.
<ng-include src="lowerTabURL"></ng-include>
This page contains a devextreme control which loads a datasource via ajax.
html:
<div class="tab-container" style="height:100%; width:100%">
<div dx-tabs="lowerTabOptions" dx-item-alias="lowerTab">
</div>
</div>
controller:
DemoApp.controller('NavigationController', function DemoController($scope, $templateCache) {
$scope.lowerTabURL = "LowerPanelTest";
$scope.currentSidebarId = 10100;
$scope.lowerTabOptions = {
dataSource: new DevExpress.data.CustomStore({
load: function (loadTabOptions) {
console.log('get tabs');
var d = $.Deferred();
$.ajax({
url: 'GetLowerTabs',
data: { currentSidebarId: $scope.currentSidebarId },
type: 'GET',
success: function (result) { console.log(result); d.resolve(result); }
});
return d.promise();
}
}),
animationEnabled: true,
swipeEnabled: true,
itemTitleTemplate: 'title',
height: '100%'
};
$scope.navBarClicked = function (sidebarId) {
console.log(sidebarId);
$scope.currentSidebarId = sidebarId;
}
});
This works correctly however I have a navbar which when clicked, should change the tab control.
Currently I am changing the sidebarId which gets passed to the ajax call but I need a way to reload the include page so that this is called again. I have tried changing the lowerTabUrl and then changing it back again but this doesnt refresh the page. What is the best way to do this?

It depends on your angular version, you will need to watch after changes of value for param sidebarId, # angular 1 this is achieved by scope.watch
scope.$watch('sidebarId', function(newValue, oldValue) {
// ..call refresh here
});
at angular 1.5 and later you can override ngOnChages
this.$onChanges = function (changesObj) {
if (changesObj.sidebarId) {
// changesObj.sidebarId.currentValue
}
};

Related

Select2 with ajax remote data options component in Vuejs

I wanna to use select2 with ajax remote data options in Vuejs 2.x. In vuejs.org website located a sample for select2 component that work as static, but I need to select2 with this specific for my project. How to convert JSFIDDLE Example to select2 that call an API with keyboard type.
In jQuery Select2 use this code for ajax call:
$('.js-data-example-ajax').select2({
ajax: {
url: 'https://api.github.com/search/repositories',
dataType: 'json'
// Additional AJAX parameters go here; see the end of this chapter for the full code of this example
}
});
Here is component that is working for me. Reference to their select2
https://v2.vuejs.org/v2/examples/select2.html
The gotcha for me was using change.select2 instead of triggering change event in the watch. change event causes infinite loop.
Your callback/ajax URL will need to return data with at least .id and .text properties. See this URL for proper format https://select2.org/data-sources/formats
<select2 v-model="member" name="member" callback="/res/member/select2.php" placeholder="Type a name"></select2>
Vue.component('select2', {
props: ['name', 'value', 'required', 'callback', 'placeholder'],
template: '<select :name="name" v-bind:class="{required: required}" class="vue-select2"></select>',
watch : {
value : function(value) {
$(this.$el).empty().append('<option value="' + value.id + '">' + value.text +'</option>').trigger('change.select2');
}
},
mounted: function() {
var that = this;
var options = {
width: '100%',
placeholder: this.placeholder,
allowClear: true,
ajax: {
url: this.callback,
dataType: 'json'
}
};
$(this.$el).select2(options);
$(this.$el).on('change', function() {
var item = $(this).select2('data')[0];
that.$emit('input', item);
});
}
});

ui-angular fullcalendar refresh issue

I'm using ui-calendar to display events. To fill out the calendar model, the controller fetches the events from a Factory. The wierd part (which I can't figure out), is that when the Factory fetches the data from the API, the calendar shows the events just fine. However, in order to "speed things up" a little, the Factory saves the api fetched data in a local variable. If the Factory returns the data from the local variable, the calendar does not display the events. However if the Factory returns data from the API, the events are displayed just fine (so there must be something wrong with the way I am returning the local variable data from the Factory).
The Factory method is as follows:
function getAll() {
if (!_allEventsRequiresUpdate && _allEvents) {
var deferred = $q.defer();
deferred.resolve(_allEvents);
return deferred.promise;
}
else {
var request = $http({
method: "Get",
url: baseUrl
});
return request.then(function (response) {
_allEvents = response.data;
_allEventsRequiresUpdate = false;
return response.data;
}, handleError);
}
}
The _allEvents variable get filled when the data is fetched from the API. The data in both cases (returned from the API or the local variable), is exactly the same (at least to my knowledge), however, as stated previously, only the data fetched from the API gets rendered in ui-calendar/fullcalendar.
Any ideas? Is there something wrong as to how I am returning the local variable from the Factory?
BTW, in both cases, the controller resolves the promise.
UPDATE
The following is the method in the Angular controller that fetches the data from the Factory:
function getAllEvents() {
serviceAppointmentsServices.getAll()
.then(function (data) {
vm.events = angular.copy(data);
vm.fullCalendarEvents = [];
for (var i = 0; i < vm.events.length; i++) {
var event = {
id: vm.events[i].xrmId,
title: vm.events[i].xrmName,
start: moment(vm.events[i].startDate).tz('America/Santiago'),
end: moment(vm.events[i].endDate).tz('America/Santiago'),
stick: true
}
if (vm.events[i].xrmStatus.value == 1)
event.color = '#D2A15D';
vm.fullCalendarEvents.push(event);
}
uiCalendarConfig.calendars["calendar"].fullCalendar('removeEventSources');
uiCalendarConfig.calendars["calendar"].fullCalendar('addEventSource', vm.fullCalendarEvents);
}, function (mesage) {
toastr.error(mesage, "error!");
});
}
Here is the calendar config:
vm.uiConfig = {
calendar: {
height: 450,
editable: true,
eventClick: editEvent,
dayClick: addEvent,
eventDrop: $scope.alertOnDrop,
eventResize: $scope.alertOnResize,
eventAfterAllRender: documentReady,
locale: 'es',
timezone: 'America/Santiago',
customButtons: {
addEvents: {
text: 'nuevo',
click: function () {
vm.fx.addEvent();
$scope.$apply()
}
}
},
header: {
left: 'month basicWeek basicDay agendaWeek agendaDay',
center: 'title',
right: 'addEvents today prev,next'
},
eventRender: eventRender
}
};
I'm posting the answer in case anyone else out there gets into the same issue.
Thanks to #Javarome (https://stackoverflow.com/users/650104/javarome) in the post: Directive is being rendered before promise is resolved. I followed his suggestion and everything worked like a charm.
Summary: the issue was that the directive was getting fired before the promise resolved in the controller. So I followed his suggestion to wrap the directive in an ng-if (with the variable needed to be resolved as the trigger, and voila!!! Something like this:
<div class="container" ng-if="vm.fullCalendarEvents">
<div class="calendar" ng-model="eventSources" calendar="calendar" config="uiConfig.calendar" ng-disabled="waitingForHttp" ui-calendar="vm.uiConfig.calendar" ></div>
</div>

Howto submit a form with Angular and displaying results on a different page

I'm trying to submit a form from a HTML page using angular.
My HTML code is:
<form role="search">
<input type="text" ng-model="searchSring">
<button type="submit" ng-click="searchPerson(searchString);">Get it!
</button>
</form>
The searchPerson function is calling some PHP page using Ajax and data is successfully retrieved from it.
What I want is when the user has clicked the Get it! button, he should be routed to another HTML page where I would like to display the results. I've tried using "action=" in the form and even calling window.location once Ajax completed to route to the next page. Every time the result is cleared. I've tried using factory with get/set, but this too clears the data on the second page after the window.location call.
Here's the factory code:
myApp.factory('searchService', function(){
var searchService = {};
var mySearchResult = {};
searchService.set = function(searchResult){
mySearchResult = searchResult;
}
searchService.get = function(text){
return mySearchResult;
}
return searchService;
});
CONTROLLER
myApp.controller('OnlineCVController', function($scope, searchService) {
$scope.searchPerson = function(personString) {
$.ajax({
url: "mySearch.php",
type: 'POST',
data: { Person: personString },
async: false, success: function (result) { searchService.set(result);
console.log(result);
window.location = "search.html";
}, error: function (result) { } });
}
Can anyone guide me further?

Having trouble making page change work when set from url

I'm building an app using AngularJS and OData Controller. I created the pagination using Angular-ui.
<div class="table" ng-controller="MyCtrl as ctrl">
<!-- bunch of data to be shown here - The table stuff -->
<uib-pagination class="pagination"
total-items="ctrl.totalItems"
items-per-page="10"
max-size="10"
rotate="false"
boundary-links="true"
ng-model="ctrl.currentPage"
ng-change="ctrl.pageChanged(ctrl.currentPage)">
</uib-pagination>
</div>
This works perfect. What happened was when user goes to the next page, select a table for detail view, then click 'Done' or 'Cancel' or whatever button to get out of the detail view to the table view, the view is set back to first page instead of taking them back to whatever page they were before.
So, what I ended up doing, is creating a state using ui-router.
Here's the ui-router state
.state('Claims', {
url: '/Claims?page',
templateUrl: baseUrl + 'Scripts/App/Views/Template/denied/denied-claims-table.html',
params: {
page: {
value: '0',
squash: true
}
}
})
.state('Detail', {
url: '/Claims?page&id/detail',
templateUrl: baseUrl + 'Scripts/App/Views/Template/denied/denied-claims-details-panel.html',
params: {
page: {
value: '0',
squash: true
},
id: {
value: '0',
squash: true
}
}
})
And here's my controller:
deniedClaimsApp.controller('DeniedClaimsController', [
'$scope',
'$state',
'$stateParams',
'DeniedClaimsService',
'SharedDataService',
function ($scope, $state, $stateParams, DeniedClaimsService, SharedDataService) {
var vm = this;
var claimBK = {};
vm.claims = {};
vm.totalItems;
vm.numPages = 10;
vm.currentPage = parseInt($stateParams.page, 10) || 1;
console.log('Current Page: ' + $stateParams.page);
activate();
SharedDataService.registerObserver(activate);
function activate() {
$scope.$emit('LOAD');
vm.isCollapsed = true;
console.log("Page set to : " + vm.currentPage);
//vm.currentPage = DeniedClaimsService.getCurrentPage();
vm.currentPage = $stateParams.page;
vm.claims = DeniedClaimsService.getClaims(vm.currentPage);
angular.copy(vm.claims, claimBK);
resolve();
$state.go('.', { page: vm.currentPage }, { notify: false });
}
function resolve() {
vm.currentPage = $stateParams.page; //adding this didn't help either
console.log("Resolve: " + vm.currentPage);
vm.claims.$promise.then(function (data) {
vm.totalItems = data.count;
$scope.$emit('UNLOAD');
});
}
vm.pageChanged = function (page) {
/*
This is where page is always 1. For some reason, when the page number is changed from the url, it raises the page change event, but the ng-model in uib-pagination doesn't change to the page set in the url. It always stays 1 and changes the page back to the first page
*/
$scope.$emit('LOAD');
//vm.currentPage = $stateParams.page;
console.log("New page: " + vm.currentPage);
console.log('changing page');
vm.claims = DeniedClaimsService.pageChanged(vm.currentPage);
vm.claims.$promise.then(function (data) {
$scope.$emit('UNLOAD');
});
console.log("Changing State to: " + vm.currentPage);
$state.go('.', { page: vm.currentPage }, { notify: false });
console.log("Changing pagination: " + vm.currentPage);
//vm.currentPage = $stateParams.page;
}
So, the controller is only there to change the page, and a couple other things that is not shown here for brevity. When I change the page using the 'Next' or 'Prev' buttons, the page changes fine. But when I change the page from the url and obtain the page from $stateParams.page, it changes the page back to first page no matter which page I was in. I thought it had something to do with the page change event raised when using ng-change. So, I changed uib-pagination ng-change to ng-click="ctrl.pageChanged(ctrl.currentPage). Doing this did change the page when the page number is set in the url as /Claims?page=5then it'd take me to page 5, but it didn't change the ng-model in uib-pagination. That remained 1 even though the table is displaying data for page 5. So, after changing to page 5 from the url, and if I change the page by clicking 'Next', it would take me to page 2 instead of page 6. What am I doing wrong? Why is that model not changing with the change in value for the same model?

$http.get method not working on ng-submit

I want $http.get method to work when a form is submitted.
Here is my code. The object $scope.questions is being set when the method is called but the data doesn't show up in the div. Moreover, when the $http.get method is outside the signIn() function it works just fine.
$scope.signIn = function(data) {
$location.path('/profile');
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$scope.questions = questionData;
console.log($scope.questions);
});
};
<div>
User Profile
<br/>Question Posted
<br/>
<input ng-model="query.title" id="value" type="text" placeholder="Search by Title..." ">
<div>
<ul>
<li ng-repeat="question in questions | filter: query ">
{{question.title}}
</li>
</ul>
</div>
<br/>
</div>
You need to move your $location.path('/profile') inside your http request. Remember that a http request is async call. You should redirect after getting the data not before.
$scope.signIn = function(data) {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$scope.questions = questionData;
console.log($scope.questions);
$location.path('/profile');
});
};
If you're redirecting to another route with a completely separate scope you will lose any scope you're setting in the success handling.
From what I'm reading you're clicking a button to do an action. After that action you're redirecting to another page with a separate controller and trying to persist the data.
Unfortunately, Angular hasn't figured out a great way to do this. The easiest way to persist data through controllers and scope is to create a service that will store it in one controller and grab it in another controller.
For instance:
$scope.signIn = function(data) {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(questionData) {
$location.path('/profile');
storageService.store("question", questiondata)
});
};
Your new factory to persist data through:
angular.module('moduleName').factory('storageService', [
function () {
return {
store: function (key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get: function(key) {
return JSON.parse(localStorage.getItem(key));
},
remove: function(key) {
localStorage.removeItem(key);
}
}
}
]);
Other controller to access data:
$scope.question = storageService.get("question");
// remove localstorage after you've grabbed it in the new controller
storageService.remove("question");
An alternative to doing the somewhat 'hacky' way of using localStorage to persist data through controllers is to use ui-router and have a resolve on the route you're redirecting to.
For instance:
$scope.signIn = function(data) {
$state.go('profile');
};
In your route file:
.state('profile', {
url: '/profile'
controller: profileControllerName,
templateUrl: 'profileHtmlTemplate.html',
resolve: {
'questions': [function() {
var url = "database/fetch_data.php?query=";
var query = "Select * from question where userId=2";
url += query;
$http.get(url).success(function(res) {
return res.data;
});
}]
}
}
In your profile controller:
Inject your 'questions' resolve into your controller and assign `$scope.question = questions;
This will make the HTTP call as soon as you click the route, return the data if successful, then render the page. It will NOT render the page if the resolve does not return success. This will ensure your data will be loaded before you load the page that depends on that data.
I would highly recommend using services to hold your HTTP calls for specific parts of your application. If you have a GET questions, POST question, PUT question. I would create a questionService and make all my HTTP methods there so you don't have to clutter your routes. You would only have to call:
.state('profile', {
url: '/profile'
controller: profileControllerName,
templateUrl: 'profileHtmlTemplate.html',
resolve: {
'questions': [function() {
return questionService.getQuestions(id).then(function(res) {
return res.data;
})
}]
}
}

Resources