I am using a static json file to simulate my server and getting my array of orders from it.
I'm presenting the orders in a table in my html file with the option of deleting one from it.
Each time I load the html file the full list gets loaded, with the orders I have deleted throught the controller function.
How can I loat the data from the factory only once?
Here is my controller:
app.controller("MainPageCtrl", function($scope, getOrdersFactory)
{
$scope.orders = [];
// Getting the data frm the facrory
var dataPromise = getOrdersFactory.getDataFunc();
dataPromise.then(function(data){
$scope.orders = data.orders;
});
// Deletes an orders.
$scope.deleteOrder = function(order){
// Finds the index of the order.
var orderIndex = $scope.orders.indexOf(order);
// Delete the order.
$scope.orders.splice(orderIndex, 1);
};
});
By default angular services and factories are singletons(loaded only once). The problem you are facing is with controller re-initialization. When route change happens the controller is re-initialized so therby getting the previous value from the factory.
You can use a setter function on your 'getOrdersFactory'.
Assuming your 'getOrdersFactory' to be
app.factory('getOrdersFactory',function(){
//code to read from file and set the file on a variable orderDetails
var orderDetails = contentsReadFromFile;
return{
getDataFunc:function(){
return orderDetails
},
setDataFunc:function(modifiedOrderDetails){
orderDetails = modifiedOrderDetails;
//code to set the new content to the static file
}
}
}
code to read the file from the static file will be rendered when you inject the factory for the first time, and on your controller set the order details on the delete function
// Deletes an orders.
$scope.deleteOrder = function(order){
// Finds the index of the order.
var orderIndex = $scope.orders.indexOf(order);
// Delete the order.
$scope.orders.splice(orderIndex, 1);
getOrdersFactory.setDataFunc($scope.orders);
};
I guess you are losing your data i.e $scope.orders .If this is the scenario just change
dataPromise.then(function(data){
$scope.orders = data.orders;
});
to
dataPromise.then(function(data){
$scope.orders = angular.copy(data.orders);
});
Related
I have json file in which i pernamently rewrite data from my database ,so inside it i have several json object ( i mean i have json array inside my json File) i want to make one form for one json object for this reason i have used embedde forms i mean user task form and angular ui , here is my code:
v
ar jsonFile;
inject([ ‘$scope’, ‘$http’, ‘$location’, ‘Uri’, function($scope, $http, $location, Uri) {
camForm.on('form-loaded', function () {
$http.get(Uri.appUri("engine://engine/:engine/process-definition/key/my-process-key/startForm")).success(function(result){
var contextPath = result.contextPath + '/forms/';
var filePath = contextPath + 'data.json';
$.getJSON(filePath, function(json) {
jsonFile = json;
});
});
});
var jsonData1=JSON.stringify(jsonFile);
var rawData=JSON.parse(jsonData1);
var documentData = $scope.documentData = {
"id":rawData[i]["id"],
"organizationNameGE":rawData[i]["organizationNameGE"],
"organizationNameEN":rawData[i]["organizationNameEN"],
"cardNumber":rawData[i]["cardNumber"]
};
camForm.on('form-loaded', function() {
camForm.variableManager.createVariable({
name: 'documentData',
type: 'json',
value: documentData
});
});
but it throws exception that i have Unexpected end of input, but when i replace file data with custom data it works perfectly , what am i missing here?
how can i manage to generate one form for each json data object at a time?
Also i have tried this:
I have added TaskListener in user task process in java it looks like this
public class FormListener implements TaskListener {
public void notify(DelegateTask arg0) {
long id = (Long) arg0.getVariable("id");
String organizationNameGE=(String) arg0.getVariable("organizationNameGE");
String organizationNameEN=(String) arg0.getVariable("organizationNameEM");
String cardNumber=(String) arg0.getVariable("cardNumber");
arg0.setVariable("id",id);
arg0.setVariable("organizationNameGE",organizationNameGE);
arg0.setVariable("organizationNameEN",organizationNameEN);
arg0.setVariable("cardNumber",cardNumber);
}
}
and i also have this code inside my embeded form script:
inject(['$scope', '$http', function($scope, $http) {
var variableManager = camForm.variableManager;
// OnFormLoaded
camForm.on('form-loaded', function() {
// Fetch Variables
// - General
variableManager.fetchVariable('processInitiator'); // set by the engine
// - Process
variableManager.fetchVariable('id'); // set in an earlier form
variableManager.fetchVariable('organizationNameGE');
variableManager.fetchVariable('organizationNameEN');
variableManager.fetchVariable('cardNumber');
});
// OnVariablesFetched
camForm.on('variables-fetched', function() {
// After the variables are fetched, bind the value to the angular scope
// - General
$scope.processInitiator = variableManager.variable('processInitiator').value;
// - Process
$scope.id = variableManager.variable('id').value;
$scope.organizationNameGE= variableManager.variable('organizationNameGE').value;
$scope.organizationNameEN = variableManager.variable('organizationNameEN').value;
$scope.cardNumber=variableManager.variable('cardNumber').value;
});
but it doens;t gives me any result i mean it trows exception like this
SPIN/JACKSON-JSON-01004 Unable to find 'id'
what should i change to make my code work?
Just create a execution listner which executed at start of the user task, you can make it in the diagram. In the Listner implementation read the JSON as key value pair , set the key as camunda variable name and value as well. Now in the form give cam variable as the key that you have given in Listner implementation. You can implement the Listner in JavaScript /Java.
I've a problem that, unfortunately, I was not able to solve in a while, even looking at related StackOverflow Q/A.
I'm building an application using MEAN and I'm having an issue
when I need to render new items trough ng-repeat.
I have lots of items stored in a MongoDB instance, and I'm perfectly
able to fetch all of them trough API calls.
I need to show only 24 items at the very beginning, and 24 more every
time the user clicks on a show more button. I always need to
concatenate them after the old ones.
It works perfectly with the first 24 items but It does not render
other items.
When I try to log the new fetched items, I get them with no problems.
I'm able to see their attributes and so on.
This is a short cut of my items View:
<div class="myItem" ng-repeat="item in searchCtrl.items track by $index">
. . . .
</div>
This is my Show More Button:
<a class="showMoreButton" ng-click="searchCtrl.goToNextPage()">show more</a>
This is a simplified version of my Controller also known as searchCtrl:
function SearchController($scope, ItemFactory) {
var vm = this;
//Needed for pagination, 24 items at a time, starting from page 1
vm.searchParams = {
size : 24,
page : 1
}
//Initialize Empty Array to Contain Items
vm.items = [];
/*Calling fetchItems to fetch the items the very
first time the Controller is called*/
fetchItems();
//Calls goToPage passing it a new page (It handles pagination)
vm.goToNextPage = function() {
var next = parseInt(vm.info.currentPage) + 1;
vm.goToPage(next);
};
//Calls fetchItems after setting the new page
vm.goToPage = function(page) {
vm.searchParams.page = page;
fetchItems();
};
//Calls getItems and pushes the single items into vm.items
function fetchItems(){
ItemFactory.getItems(vm.searchParams).then(function(response){
//iterates trough items
for (var i = 0; i < response.data.data.length; i++) {
//Log current item
console.log(JSON.stringify(response.data.data[i]));
//push current item into vm.items
vm.items.push(response.data.data[i]);
}
//Print correctly the new items pool
console.log(vm.items);
}, function(error){
$log.error(error);
});
}
};
This is a simplified version of my ItemFactory:
angular.module('myApp').factory('ItemFactory',
function ($http, API_URL) {
//Getting items from API
function getItems(params) {
return $http.get(API_URL + '/item',{params: params}
).then(function success(response) {
return response;
});
}
return {
getItems : getItems
}
});
Controller binding to my view, it work as it should. I'm using this modularized approach and it always works perfectly:
'use strict';
angular.module('myApp')
.config(itemRoute);
function itemRoute($stateProvider) {
$stateProvider
.state('index.items', {
url : 'index/items',
parent : 'index',
templateUrl : 'app/main-pages/items/items.html',
controller : 'SearchController',
controllerAs : 'searchCtrl'
});
}
I also tried using concat instead of looping trough items with a for but the result does not change:
//Instead of looping
vm.items = vm.items.concat(response.data.data);
Essentially:
I'm only able to render the first 24 items
I can not render all the other items even if they get properly inserted into items array
Items starting from 25 and so on do not get into the DOM
I already tried using $scope.$apply(); but I get digest errors
Questions:
What is causing this?
How can I solve this issue?
Thanks in advance, if you need any clarification just post a comment below.
I managed to solve this issue broadcasting a message from ItemFactory when fetching new items and attaching a listener to that message in SearchController. When ItemDataRefresh gets broadcasted, then, SearchController concatenates the new data.
ItemFactory:
function getItems(params) {
return $http.get(API_URL + '/item',{params: params}
).then(function success(response) {
$rootScope.$broadcast('refreshData', response.data);
return response;
});
}
SearchController:
function fetchItems(){
ItemFactory.getItems(vm.searchParams).then(function(response){
//When vm.items is empty
if (!vm.items.length) {
vm.items = vm.items.concat(response.data.data);
}
//on refreshData
$scope.$on('refreshData', function(event, data){
vm.items = vm.items.concat(data.data);
});
}, function(error){
$log.error(error);
});
}
I know that I should not use rootScope so I'm still looking for a way to make it work in a cleaner way.
I hope it will help someone.
I have a repeating piece of code that pops up in my controllers:
// Get first product from list
Product.get_details( id )
.success(function ( data ) {
// Setup product details
$scope.active_product = data;
});
I want to put this into a factory so I can DRY my code.
The problem happens when I need to access $scope.active_product and have it watched by the digest loop.
Inside Product factory:
// ajax function returns product data
var get_details = function( id ){ ... }
var set_active_product = function( active_product, id ){
// Get first product from list
get_details( id )
.success(function ( data ) {
// Setup product details
active_product = data;
});
};
And inside my controller
Product.set_active_product( $scope.active_product, id );
This works but $scope is not being monitored by the $digest loop.
Is there a way to do this without passing in a $scoped variable?
Thanks to #PetrAveryanov for pointing out $resource.
Use $resource to get the data and initially populate the $scope.active_product with an empty object. That means that active_product only shows when it's populated by $resource.
Inside Product factory
return $resource('/path/to/resource');
Inside controller
$scope.active_product = Product.get({ id: id });
I am trying to figure this out the best way to do this. I am trying to insert data into a WebSQL table and then select the data from the table and display on the screen using ng-repeat. I am using this Angular WebSQL Module https://github.com/paulocaldeira17/angular-websql#select-all.
So far, I can get the remote data and insert them into the local database. When I try to call the insert data, $scope.localproducts shows an empty array - console.log( $scope.localproducts) shows an empty array.
I use localproducts scope for my ng-repeat.
I can't get to return the ProductsFactory.localproducts array to my controller from the Factory's selectAllData function.
When clicks a button on my page, it calls the insertData function in my Controller.
What have I done wrong here? I am pretty new to angular so I would very much appreciate if someone can help me to improve the below code or suggest if there is a better way to do this.
.controller('DownloadProductsCtrl', ['$scope','ProductsFactory', function ($scope, ProductsFactory){
$scope.products = ProductsFactory.products;
$scope.localproducts = ProductsFactory.localproducts;
$scope.insertData = function(){
ProductsFactory.getRemoteData().then(function(results){
$scope.localproducts = ProductsFactory.localproducts;
console.log( $scope.localproducts); //This shows an empty array
});
}; }])
.factory('ProductsFactory', ['$webSql', function($webSql){
db = $webSql.openDatabase('myappdb', '1.0', 'Test DB', 2 * 1024 * 1024);
ProductsFactory = {};
ProductsFactory.products = [];
ProductsFactory.localproducts = [];
ProductsFactory.getRemoteData = function () {
return $http.get('./products/list.json')
.success(function (data) {
ProductsFactory.products = data;
ProductsFactory.insertData(data);
})
.error(function () {
console.error('Error');
});
};
ProductsFactory.insertData = function (data){
angular.forEach(data, function(value, key) {
db.insert('products', value).then(function(results) {
<!-- In here I like to count the total inserted items and display it on the page, but not sure sure how to send it to a scope in my controller -->
});
});
ProductsFactory.selectAllData();
};
ProductsFactory.selectAllData = function(){
db.selectAll("products").then(function(results) {
for(var i=0; i < results.rows.length; i++){
ProductsFactory.localproducts.push(results.rows.item(i)); //This added data to the array successfully.
}
console.log(ProductsFactory.localproducts); //This shows an empty array
});
};
return ProductsFactory;
}]);
Try with this resource as a start point.
https://gist.github.com/jgoux/10738978
https://github.com/paulocaldeira17/angular-websql/blob/master/angular-websql.js
The first one is very basic and easier to understand. The second more involved.
In my AngularJS controller I'm trying to do something relatively simple: I'm trying to populate a <select> element dynamically in the controller. To do so I need to wait for my localized UI text data to be loaded and data from my server to be loaded and this is causing a problem for me.
What my HTML Looks like:
<select
data-ng-model="group"
data-ng-options="options.value as options.label for options in userGroups">
<option>--</option>
</select>
Then my controller is actually implementing a base controller "class" which allows me to share logic between controllers:
// exampleController.js
myModule.controller('exampleController',
['$scope', '$timeout', '$routeParams', '$controller',
function ($scope, $timeout, $routeParams, $controller) {
// Instantiate the base controller class and set it's scope
// to this controller's scope. This is how the base and child
// controllers will share data and communicate.
var base = $controller('baseController', { $scope: $scope });
}]);
And here is a relevant snippet of the baseController:
// baseController.js
$scope.getDataFromUrl = function (url, cache, successFunction) {
$http.get(url, { cache: cache })
.success(function (data) {
if (!handleErrorInData(data))
{
successFunction(data);
}
});
};
$scope.getDataFromUrl(uiTextResourceUrl, true, function (data) {
$scope.uiText = data;
});
So baseController fetches the text resources when it loads and sets it to the scope when it's finished retrieving the data. exampleController on the other hand will fetch other data from the server via the getDataFromUrl() function defined in baseController like so:
$scope.getDataFromUrl(dataUrl, false, function (data) {
// Do stuff with the returned data...
};
My issue is coming from this part of the exampleController code where I populate the data of the <select> element from earlier:
// exampleController.js (Continued...)
$scope.getDataFromUrl(userGroupsUrl, false, function (data) {
initSelectDropdown(data);
});
var initSelectDropdown = function (data) {
var userGroups = [];
// Parse data retrieved from the server and populate the <select> bound data
// array with it
var index;
for (index = 0; index < data.length; ++index)
{
var newGroup = {
value: data[index],
label: data[index]
};
// One of the data entries will have a value of "", this group needs its
// label to be set to the localized string "No Group"
if (newGroup.value === "")
{
newGroup.label = '<' + $scope.uiText['NoGroup.Text'] + '>';
}
userGroups.push(newGroup);
}
// Set local userGroups to scope
$scope.userGroups = userGroups;
};
The problem I'm having is here in the initSelectDropdown() function. I need to have both the data from the server and the uiText resource data from the server, particularly the line newGroup.label = '<' + $scope.uiText['NoGroup.Text'] + '>'; where the data is being transformed in a way that is dependant on localized resources being loaded. I researched the issue and saw that using $q.all() might be a solution but unfortunately in my case there is no way for me to call $q.all() because the two calls to fetch data are being made from different functions in different controllers (data being requested from child controller and resources being requested from base controller).
In the view it's easy to fix this because if I bind an element to $scope.uiText['SomeText.Text'] then it doesn't care if SomeText.Text is undefined at first and when it is eventually populated the UI will automatically pick up on the change.
How can I make this work? Is it possible to achieve something like how binding works in the view?
For sharing code angular provides services/factory, you don't need to use base controller.
Define a factory class and add two methods, one to fetch your server data and other to fetch uiText data. these methods will return promises.
Now in your controller you can use $q.all() passing the two promises that will be resolved when ajax call is complete.
Hope it makes sense ?