know when data has finished loading(promised) from Infinite scroll factory - javascript

Below Infinite-scroll factory i am using to get data from backend, is there any where to apply $promise to this method as in controller i need to know when data has finished loading .
Factory :
app.factory('Gallery', function($http) {
var Gallery = function(media, album_type) {
this.items = [];
this.busy = false;
this.next = '/upload/list/'+ media +'/?album='+album_type+'&page=1';
this.end=false;
};
Gallery.prototype.nextPage = function() {
if (this.busy) return;
this.busy = true;
if (this.next){
var url = this.next;
}
else{
this.end=true;
this.busy = false;
return
}
$http.get(url).success(function(data) {
var items = data.results;
for (var i = 0; i < items.length; i++) {
this.items.push(items[i]);
}
this.next=data.next;
this.busy = false;
if (!data.next)
this.end=true;
this.count=data.count;
}.bind(this));
};
return Gallery;
});
In Controller;
$scope.images = $scope.images || new ScrollGallery('image', 'CRP');

I solved issue by adding $q in ininite-service , $q returns promise method .which i can use to to check if http was success to failed .
Infinite-service ::
app.factory('ScrollGallery', function($http,$q) {
var Gallery = function(url) {
this.items = [];
this.busy = false;
this.next = url;
this.end = false;
this.extra = {};
};
Gallery.prototype.nextPage = function() {
var def = $q.defer();
if (this.busy)
return;
this.busy = true;
if (this.next) {
var url = this.next;
} else {
this.end = true;
this.busy = false;
return;
}
$http.get(url).success( function(data) {
var items = data.results;
var extra = [];
if ( typeof data.extra != 'undefined') {
extra = data.extra;
}
for (var i = 0; i < items.length; i++) {
this.items.push(items[i]);
}
this.extra = extra;
this.next = data.next;
this.busy = false;
if (!data.next)
this.end = true;
this.count = data.count;
def.resolve(data);
}.bind(this));
return def.promise;
};
return Gallery;
});
In controller ::
$scope.mediacontent[$scope.slider_url] =new ScrollGallery($scope.slider_url_pass);
$scope.mediacontent[$scope.slider_url].nextPage().then(function(albums) {
$scope.mediacontent[$scope.slider_url].items[$scope.img_no].active=true;
console.log('albums returned to controller.');
},
function(data) {
console.log('albums retrieval failed.');
});

Related

odoo 12 custom pos lock screen module this.pos is null

i made a module for odoo 12 to lock the pos screen the code works fine in odoo 10, but gives error this.pos is null or this.pos.currency is undefined. in the models.js, i want to switch the orders of different cashiers but this.pos is not initialized, what should i do so that it becomes initialized?
here is my code:
odoo.define('pos_user_lock.models',
//['point_of_sale.models','point_of_sale.screens','point_of_sale.chrome'
//,'web.ajax','web.core'],
function (require) {
"use strict";
var ajax = require('web.ajax');
var screens = require('point_of_sale.screens');
var models = require('point_of_sale.models');
var chrome = require('point_of_sale.chrome');
var core = require('web.core');
var QWeb = core.qweb;
var _t = core._t;
models.Order = models.Order.extend({
initialize: function(attributes,options){
var order = models.Order.__super__.initialize.call(this,attributes,options);
if (!this.cashier)
{
this.cashier = this.pos.cashier || this.pos.user;
}
this.is_last_selected = (this.is_last_selected === undefined) ? false:this.is_last_selected;
return order;
},
finalize: function() {
var res = models.Order.__super__.finalize.call(this);
this.pos.lock_user_screen();
},
init_from_JSON: function(json) {
var user = this.get_user_by_id(json.user_id);
if (user)
this.cashier = user;
this.is_last_selected = json.is_last_selected;
models.Order.__super__.init_from_JSON.call(this, json);
},
export_as_JSON: function() {
var res = models.Order.__super__.export_as_JSON.call(this);
if (this.cashier)
res.user_id = this.cashier.id ;
if(this.pos && this.pos.get_cashier())
res.user_id = this.pos.get_cashier().id ;
res.is_last_selected = this.is_last_selected;
return res;
},
get_user_by_id: function(id) {
var users = this.pos.users;
for (var i = 0; i < users.length; i++) {
var user = users[i];
if (user.id == id)
return user;
}
},
});
models.PosModel = models.PosModel.extend({
initialize: function(session, attributes) {
models.PosModel.__super__.initialize.call(this, session, attributes);
var self = this;
alert(JSON.stringify(attributes.pos));
this.ready.then(function(){
if (self.config.auto_push_order)
self.config.iface_precompute_cash = true;
});
},
is_locked: function(){
if (
this.gui.current_popup
&& this.gui.current_popup.template == 'PasswordPinPopupWidget'
){
return true;
}
return false;
},
unlock: function(){
if (this.is_locked()){
this.gui.close_popup();
}
},
lock_user_screen: function(){
var self = this;
if (!this.config.lock_users) return;
this.gui.show_popup('passwordPin',{
'title': _t('Insert password or scan your barcode'),
});
},
get_last_order: function(){
var orders = this.get_order_list();
for (var i = 0; i < orders.length; i++) {
if (orders[i].is_last_selected) {
return orders[i];
}
}
return null;
},
set_last_order: function(order){
var orders = this.get_order_list();
for (var i = 0; i < orders.length; i++) {
if (orders[i].uid == order.uid) {
orders[i].is_last_selected = true;
}else{
orders[i].is_last_selected = false;
}
}
return null;
},
set_order: function(order){
models.PosModel.__super__.set_order.call(this, order);
this.set_last_order(order);
},
get_order_list: function(){
var orders = models.PosModel.__super__.get_order_list.call(this);
var c_orders = [];
var cashier = this.cashier || this.user;
for (var i = 0; i < orders.length; i++) {
if (cashier && orders[i].cashier.id === cashier.id) {
c_orders.push(orders[i]);
}
}
return c_orders;
},
switch_order: function(){
var self = this;
if(self.pos)
{
}
else
{
alert("self.pos is null");
}
if(self !== undefined && self != null && self.pos !== undefined && self.pos.currency != null)
{
alert("in switch order");
//console.log(this.pos.currency);
if (!self.config.lock_users) return;
var user = self.pos.get_cashier() || self.user;
var orders = self.get_order_list();
var last_order = self.get_last_order() || orders[0];
if (orders.length) {
self.set_order(last_order);
}
else {
self.add_new_order();
}
}
},
set_cashier: function(user){
models.PosModel.__super__.set_cashier.call(this,user);
if(this.pos)
{
alert("this.pos is not null in set_cashier");
}
else
{
alert("this.pos is null in set_cashier");
}
this.switch_order(this);
if (!this.table && this.config.iface_floorplan)
this.set_table(null);
},
});
return models;
});
the web page shows this.pos is null. and this.currency is null.
i found the solution by adding:
this.pos = this;
inside initialize function of PosModel.

Bootstrap Angular carousel to set active slide dynamically

I am using Bootstrap Angular carousel , what i am trying to do is set active class on load dynamically . my mediacontent[slider_url].items is loadede from backend. i dont have any promied method otherwise i would have set,
mediacontent[slider_url].items.active=true;
follwing is factory (for infinite -scroll) i am using to get image array from backend,
Image Data Factory :
app.factory('ScrollGallery', function($http) {
var Gallery = function(url) {
this.items = [];
this.busy = false;
this.next = url;
this.end = false;
this.extra = {};
};
Gallery.prototype.nextPage = function() {
if (this.busy)
return;
this.busy = true;
if (this.next) {
var url = this.next;
} else {
this.end = true;
this.busy = false;
return;
}
$http.get(url).success( function(data) {
var items = data.results;
var extra = [];
if ( typeof data.extra != 'undefined') {
extra = data.extra;
}
for (var i = 0; i < items.length; i++) {
this.items.push(items[i]);
}
this.extra = extra;
this.next = data.next;
this.busy = false;
if (!data.next)
this.end = true;
this.count = data.count;
}.bind(this));
};
return Gallery;
});
Carousel HTML :
<carousel id="myCarousel" interval="myInterval" on-carousel-change="onSlideChanged(nextSlide, direction)">
<slide ng-repeat="slide in mediacontent[slider_url].items" active="slide.active">
<div ng-if="slider_url=='image'">
<img ng-src="{[{slide.file}]}" alt="{[{slide.file}]}" style="margin:auto;width:250px;height:400px" />
</div>
</slide>
</carousel>
Is there any way where i can set active dynamically ,Please suggest .
this plunker i have tried :
http://plnkr.co/edit/VemNkVnVtnaRYaRVk5rX?p=preview
I had issue that i was not getting any $promise method for data . hence i was not able to set active class true in Array.i have added promise in service method.
In controller i am setting active class using index like
$scope.mediacontent[slider_url].items[idx].active=true
Infinite-service ::
app.factory('ScrollGallery', function($http,$q) {
var Gallery = function(url) {
this.items = [];
this.busy = false;
this.next = url;
this.end = false;
this.extra = {};
};
Gallery.prototype.nextPage = function() {
var def = $q.defer();
if (this.busy)
return;
this.busy = true;
if (this.next) {
var url = this.next;
} else {
this.end = true;
this.busy = false;
return;
}
$http.get(url).success( function(data) {
var items = data.results;
var extra = [];
if ( typeof data.extra != 'undefined') {
extra = data.extra;
}
for (var i = 0; i < items.length; i++) {
this.items.push(items[i]);
}
this.extra = extra;
this.next = data.next;
this.busy = false;
if (!data.next)
this.end = true;
this.count = data.count;
def.resolve(data);
}.bind(this));
return def.promise;
};
return Gallery;
});
In controller ::
$scope.mediacontent[$scope.slider_url] =new ScrollGallery($scope.slider_url_pass);
$scope.mediacontent[$scope.slider_url].nextPage().then(function(albums) {
$scope.mediacontent[$scope.slider_url].items[$scope.img_no].active=true;
console.log('albums returned to controller.');
},
function(data) {
console.log('albums retrieval failed.');
});

Running $http requests sequentially in AngularJS

I have an array of items on my $scope. For each of those items, I need to run three $http requests. These requests must run in a specific order, no matter whether there was a failure of not. I'm not sure how to do this elegantly, with the promise paradigm. I have a lot of duplicate code and it looks really confusing. I have to be doing this wrong. Currently, I have the following:
$scope.items = getItems();
$scope.currentIndex = 0;
$scope.executeItem = function() {
$http.get($scope.items[$scope.currentIndex].urlA).then(
function (resA) {
$scope.items[$scope.currentIndex].urlAWorks = true;
$http.get($scope.items[$scope.currentIndex].urlB).then(
function (resB) {
$scope.items[$scope.currentIndex].urlBWorks = true;
$http.get($scope.items[$scope.currentIndex].urlC).then(
function (resC) {
$scope.items[$scope.currentIndex].urlCWorks = true;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
},
function (errC) {
$scope.items[$scope.currentIndex].urlCWorks = false;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
}
)
},
function (errB) {
$scope.items[$scope.currentIndex].urlBWorks = false;
}
);
},
function (errA) {
$scope.items[$scope.currentIndex].urlAWorks = false;
$http.get($scope.items[$scope.currentIndex].urlB).then(
function (resB) {
$scope.items[$scope.currentIndex].urlBWorks = true;
$http.get($scope.items[$scope.currentIndex].urlC).then(
function (resC) {
$scope.items[$scope.currentIndex].urlCWorks = true;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
},
function (errC) {
$scope.items[$scope.currentIndex].urlCWorks = false;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
}
)
},
function (errB) {
$scope.items[$scope.currentIndex].urlBWorks = false;
}
);
}
);
};
Am I really chaining promises correctly? This looks WAY off.
Thank you
You are underusing promises :) Since .then returns a promise, you could do:
$http.get(urlA)
.then(function(dataA){
DoStuffWithA(dataA);
return $http.get(urlB);
})
.then(function(dataB){
DoStuffWithB(dataB);
return $http.get(urlC);
})
.then(function(dataC){
DoStuffWithC(dataC);
return true;
})
Just create references to those functions with a parameter binding. Instead of
$http.get($scope.items[$scope.currentIndex].urlC).then(
function (resC) {
$scope.items[$scope.currentIndex].urlCWorks = true;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
},
function (errC) {
$scope.items[$scope.currentIndex].urlCWorks = false;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
}
)
Do:
var next_thingy = function (worked) {
return function () {
$scope.items[$scope.currentIndex].urlCWorks = worked;
$scope.currentIndex = $scope.currentIndex + 1;
$scope.executeItem();
}
}
$http.get($scope.items[$scope.currentIndex].urlC)
.then(next_thingy(true),next_thingy(false));
Then chain them together:
var req1 = $http.get(...)
var thingies = {}
var thingies.next_thingy = function( worked) {
return function() {
var req = $http.get(...)
...
req.then(thingies.next_thingy2(true),thingies.next_thingy2(false))
}
}
req1.then(thingies.next_thingy(false),thingies.next_thingy(true))
var thingies.next_thingy2 = function(worked2) {
return function() {
var req2 = $http.get(...)
...
req2.then(thingies.next_thingy3(true),thingies.next_thingy3(false);
}
}
var thingies.next_thingy3 = function(worked3) {
return function() {
...
}
}
You can fork them all off in parallel and then wait for them to finish with:
var third_reqs = []
$scope.items.forEach(function(item) {
var third_req_defer = $q.defer()
third_reqs.push(third_req_defer.promise)
...
var thingies.next_thingy3 = function(worked3) {
return function() {
...
third_req_defer.resolve()
}
}
})
$q.all(third_reqs).then(
function() { $log.log("Finished!")},
function(){ $log.error("some third reqs failed.")})

ko.computed not evaluating when dependent values change

I created this fiddle http://jsfiddle.net/mj9f9/4/
The view does not update the enabled status of buttons "Search" and "Create". Only once it happen when the user select a product class, but it must happen also when the user changes a value of a component.
The view is a search view enabling the user to search products identified by components that depend on the class of product selected.
The view model:
/// ProductClass
function ProductClassModel() {
this.Id = 0;
this.FullCode = "";
this.Name = "";
this.EntitiClass = "";
this.CompClasses = [];
}
/// Component class that is part of a product class
function ComponentClassModel() {
this.Id = 0;
this.FullCode = "";
this.Name = "";
this.ProductClassId = 0;
this.ComponentClass = "";
}
/// The product, it is the composition of a product class with values for each of its components
function ProductModel() {
this.Id = ko.observable(0);
this.Uid = ko.observable("");
this.FullCode = ko.observable("");
this.Name = ko.observable("");
this.EntitiClass = ko.observable("");
this.Components = ko.observable([]);
}
/// ComponentValue is a class of component with a value (actually an instance of that class of component)
function ComponentValueModel() {
this.Id = ko.observable(0);
this.FullCode = ko.observable("");
this.Name = ko.observable("");
this.ProductClassId = ko.observable(0);
this.ProductId = ko.observable(0);
this.ComponentClass = ko.observable("");
this.Value = ko.observable();
}
/// Wrapper of ComponentValueModel with convenient observable properties (We cannot modify the original ComponentValueModel because it is extern)
function ComponentStateViewModel(prodcomp) {
var self = this;
console.log("CREA ComponentStateViewModel " + prodcomp);
self.value = prodcomp.Value();
self.component = prodcomp;
self.changed = ko.observable(false);
self.found = ko.observable(false);
self.searched = ko.observable(false);
self.required = true;
self.isCreatable = ko.computed(function () {
return self.searched() && !self.found();
});
self.isDefined = ko.computed(function () {
return self.component.Value() !== undefined;
});
self.component.Value.subscribe(function () {
var newval = self.component.Value();
if (newval !== self.value) {
self.changed(true);
self.found(false);
self.searched(false);
self.value = newval;
}
});
}
/// View model
function ProductViewModel() {
var self = this;
self.customerId = ko.observable(111);
self.prodClasses = ko.observable([]);
self.currentProdClass = ko.observable();
self.currentProd = ko.observable();
self.currentUid = ko.observable();
self.productsFound = ko.observableArray();
self.componentStates = ko.observableArray();
self.productFound = ko.computed(function () {
var prod = self.currentProd();
return self.prodClassSelected && (prod !== undefined && prod.Uid() !== undefined);
});
self.customerSelected = ko.computed(function () {
return self.customerId() > 0;
});
self.prodClassSelected = ko.computed(function () {
return self.currentProdClass() !== undefined;
});
self.canSearch = ko.computed(function () {
if (!self.prodClassSelected() || !self.productFound()) {
return false;
}
var inuid = self.currentUid();
var puid = self.currentProd().Uid();
if ((inuid !== undefined) && (inuid !== puid) && (inuid.length > 5)) {
return true;
}
var comps = self.componentStates();
for (var i = 0; i < comps.length; i++) {
var c = comps[i];
if (c.isDefined && !c.searched) {
return true;
}
}
return false;
});
self.canCreate = ko.computed(function () {
if (!self.prodClassSelected() || self.productFound()) {
return false;
}
var cstates = self.componentStates();
for (var i = 0; i < cstates.length; i++) {
var cm = cstates[i];
if (!cm.component.Value()) {
return false;
}
if (!cm.isCreatable()) {
return false;
}
}
return true;
});
self.clear = function () {
self.componentStates([]);
var c = self.currentProdClass();
if (c !== undefined) {
self.currentUid(undefined);
self.currentProd(undefined);
}
};
self.initialize = function (compClassesData) {
self.prodClasses(compClassesData);
};
self.currentUid.subscribe(function () {
var uid = self.currentUid();
if (uid === undefined) {
return;
}
var prod = self.currentProd();
if ((prod === undefined) || (prod.Uid() !== uid)) {
if (uid.length < 5) {
return;
}
self.currentProd(new ProductModel());
}
});
self.currentProdClass.subscribe(function () {
self.clear();
var c = self.currentProdClass();
if (c === undefined) {
return;
}
var psearch = new ProductModel();
psearch.FullCode(c.FullCode);
psearch.Name(c.Name);
psearch.EntitiClass(c.EntitiClass);
for (var i = 0; i < c.CompClasses.length; i++) {
var cca = c.CompClasses[i];
var comp = new ComponentValueModel();
comp.FullCode(cca.FullCode);
comp.Name(cca.Name);
comp.ProductClassId(cca.ProductClassId);
comp.ComponentClass(cca.ComponentClass);
psearch.Components().push(comp);
self.componentStates.push(new ComponentStateViewModel(comp));
}
self.currentProd(psearch);
self.currentUid(psearch.Uid());
});
self.searchProduct = function () {
var compfilter = [];
var comps = self.currentProd().Components();
for (var i = 0; i < comps.length; i++) {
var c = comps[i];
if ((c.Value() !== undefined) && (c.Value() !== "")) {
var filter = new ComponentValueModel();
filter.FullCode(c.FullCode());
filter.ComponentClass(c.ComponentClass());
filter.Value(c.Value());
compfilter.push(filter);
}
}
};
self.createProduct = function () {
// TODO
};
}
The problem is with the buttons Search and Create. The first one is enabled or disabled by a computed function that involves several observables but the one I am interested in is the Value of a component of the class ComponentValueModel.Value:
<button data-bind="click: searchProduct, enable: canSearch()">Search</button>
The code I expected to enable or disable this button is defined in ProductViewModel.canSearch computed function:
self.canSearch = ko.computed(function () {
if (!self.prodClassSelected() || !self.productFound()) {
return false;
}
var inuid = self.currentUid();
var puid = self.currentProd().Uid();
if ((inuid !== undefined) && (inuid !== puid) && (inuid.length > 5)) {
return true;
}
var comps = self.componentStates();
for (var i = 0; i < comps.length; i++) {
var c = comps[i];
if (c.isDefined && !c.searched) {
return true;
}
}
return false;
});
It seems as if ko does not notifies the change of value in the observable component.Value. Any help will be appreciated.

Javascript Array indexFirst

I build a prototype that handle pages, I successfully add (push), but can get the data, I failed:
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
Here the javascript page handler:
var Pages = new Array();
PageContainer = function () //constructor for the proxy
{
// this._baseURL = url;
};
PageContainer.prototype =
{
AddPage: function (data) {
if (data == null) return;
Pages.push({ PageID: data.PageID, SegmentID: data.SegmentID });
},
GetPage: function (PageID) {
alert('getPage('+PageID+')=' + JSON.stringify(Pages));
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
var dt = { PageID: Pages[foundImageIndex].PageID, SegmentID: Pages[foundImageIndex].SegmentID };
return dt;
}
};
I call from other js as following:
var gPageContainer = new PageContainer();
for (var i = 0; i < SegStruct.SegmentsCount; i++) {
var segRClass = //get from webservice
gPageContainer.AddPage({ PageID: i, SegmentID: segRClass.SegmentID });
}
I trying to call: gPageContainer.GetPage(1); but it failed in GetPage: function (PageID) it returns -1 in:
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
foundImageIndex always -1
why?
Simply add the following before the constructor:
if (typeof Array.prototype.indexFirst == 'undefined') {
Array.prototype.indexFirst = function (validator) {
for (var i = 0; i <= this.length - 1; i++) {
if (validator(this[i])) {
return i;
}
}
return -1;
};
}

Categories