I have a simple ng-repeat block that looks like this:
<div ng-repeat = "Service in getServices()">
{{Service}}
</div>
The corresponding controller defines getServices()
$scope.getServices = function(){
try{
var services = [];
for (var i = 0; i < $rootScope.Store.Services.length; i++){
services.push($rootScope.Store.Services[i].ServiceID);
}
console.log('services: ' + JSON.stringify(services))
return services;
}
catch (err){
console.log('no services')
return [];
}
};
For some reason, however, I am getting no Services in my view. I know I can just repeat directly over the $rootScope and that's how I had it before but this was an effort to debug. I am getting Services in my console:
services: ["ATM","DELI","DIESEL"]
Also, when I change the getServices() function to something like this:
$scope.getservices = function(){
var test = ["a", "b", "c"];
return test;
}
It does update the view correctly. Not sure what's going on! Note that I have many other perfectly working ng-repeats in the app.
Solved
I have no idea why but after removing iscroll from this particular page, it works fine -_-
Since you mention that iScroll was the problem, have you checked there aren't any global variable collisions?
Maybe you should implement iScroll via Angular: http://ngmodules.org/modules/ng-iScroll
Related
I've got a PhoneGap application in development where I'm trying to use framework7's search bar to filter out my virtual list of products.
Current functionality is that the list works fine, but the search bar only searches through the rendered elements rather than the whole virtual list.
I've gone through framework7's documentation on getting their virtual list and searchbars to work together, but as far as I can tell the searchbar in my code completely ignores the virtual lists searchAll function which I put in. I can have searchAll() return anything and it makes no difference to the current functionality.
var listObject = {
items: selectProd,
template: '<li class="item-content"><div class="item-inner"><div data-value="{{model_id}}" class="item-title list-title">{{internal_descriptn}}</div></div></li></script>',
searchAll: function (query, items) {
var foundItems = [];
for (var i = 0; i < items.length; i++) {
// Check if title contains query string
if (items[i].title.indexOf(query.trim()) >= 0) foundItems.push(i);
}
// Return array with indexes of matched items
return foundItems;
}
};
console.log(listObject);
var virtualList = myApp.virtualList('#product-list', listObject);
var mySearchbar = myApp.searchbar('.searchbar', {
searchList: '.list-block-search',
searchIn: '.list-title'
});
I feel like the only thing I could be missing is some way to put the virtualList into the searchbar as an attribute or similar to link them, it seems strange for me to expect them to just work together like magic. Yet that seems to be what the documentation suggests it does (not in my case apparently or it would work). Thanks for any help.
Solved it by looking at an example on their github. At first glance everything is the same, so I copy it over and slowly change it back to include my data to see where the problem occurs. For some godamn reason, you need to use the class virtual-list to identify the parent containing your list. Then specify that class for your virtual list and for your search bar. Using a different name instead won't work. Very frustrating that this isn't mentioned anywhere at all in documentation.
Is there a way of checking if an directive in angular exists?
What I want to do, oder better what I have:
A Collection of 'protocols', which share some similarities, such as: name, created by, last edited, comment etc., but they all have special fields.
I have this one directives which matches with all those protocols. Showing the name and all the things which all the protocol have in common.
Within this directive I want to check if a special (more specific) view of the given protocol is available. In my case I call it "CompactView". The CompactView will give more detailed information of this protocol, it should be displayed within the actual directives. So a nested directive - no big deal.
My first approched worked fine, I had an array which had the protocol name as key, and directive html element (string) as value:
let decider = {
'cardiovascular_function': '<hcd-Cardiovascular-Function-Compact-View protocol="protocol"/>'
};
//use suitable directive
let protocolDirective = decider[scope.protocol.name];
let templateHook = angular.element(element).find('.extend-protocol-info')[0];
//use base template
//hooks protocol directive into template if possible
if (typeof protocolDirective != 'undefined') {
let compiled = $compile(angular.element(protocolDirective))(scope);
angular.element(templateHook).html(compiled);
scope.defaultTxt = false;
}else{
scope.defaultTxt = true;
}
If no key exited within the decider array I will display some default txt explaining, that there is no CompactView available.
The application will likely grow, and a lot of protocols will follow, so when ever someone creates a protocol the decider array needs to be extend. Prone to failure, and it would be much nicer if I can just check if a directive with some name exists and compile it.
My new approached look like the following:
let protocolName = scope.protocol.name;
let directiveName = 'hcd' + _.capitalize(_.camelCase(protocolName)) + 'CompactView';
//example: <hcd-Cardiovascular-Function-Compact-View protocol="protocol"/>
console.log(directiveName);
console.log($injector.has(directiveName));
try {
console.log(angular.module('hcdProtocol').directive(directiveName));
} catch (err) {
console.log(err);
}
//check if directive for given protocol exists
if ($injector.has(directiveName)) {
scope.defaultTxt = false;
let templateHook = angular.element(element).find('.extend-protocol-info')[0];
let protocolDirective = '<hcd-' + _.kebabCase(protocolName) + '-Compact-View protocol="protocol" />';
let compiled = $compile(angular.element(protocolDirective))(scope);
angular.element(templateHook).html(compiled);
} else {
//display default if no compact view exists
scope.defaultTxt = true;
}
So $injector.has is not working, since directives are not registered within $provide. Redeclaring and checking for errors, the try catch block, is not working either.
I'm currently trying to understand $compileProvider, somewhere within angular is the information which directive exist, I would love to find it.
Any ideas or suggestions, on how to fix this "generic directive" approach?
Maybe my concept with this nested directives is wrong, and there is a much simpler approach?
Both code blocks are within the link function of directive()
I am currently trying ionic. I am not really used to this kind of web dev so I might be totally off-track. Anyway, I want to access an SQLite DB and add the results to a ion-slide-box.
I was trying something like that :
function selectResultSuccess(tx, results)
{
var div = "";
div += "<ion-slide-box >";
for (var i = 0 ; i < len ; i++)
{
div+="<ion-slide>"
div+= results.rows.item(i).Result ;
div+="</ion-slide>"
}
div += "</ion-slide-box >";
$(".result-list").html(div);
}
HTML :
<ion-content ng-controller="ExampleController" class="result-list">
</ion-content>
app.js :
angModule.controller("ExampleController", function($scope, $ionicSlideBoxDelegate) {
$scope.navSlide = function(index) {
$ionicSlideBoxDelegate.slide(index, 500);
}
$scope.nextSlide = function() {
$ionicSlideBoxDelegate.next(500);
}
$scope.update = function() {
$ionicSlideBoxDelegate.update();
}
});
So this does not work, the slidebox does not get updated and I got all my results on the same page (instead of having them on different slides), I have tried multiple things and I believe this is not the best way to handle that but I can't find anything that matches my needs.
I am also trying to avoid working with SQLite plugins.
So, you're going at it completely wrong, but that's ok. You're making the beginner mistake of still being in the JQuery mindset instead of the Angular mindset. Everyone goes through it.
So, Angular is based on templates, not DOM manipulation (with the exception of directives). What you want to do is build a template that does an ng-repeat on a set of slides, stored in some kind of scope variable.
Let's start with this:
<ion-content ng-controller="ExampleController" class="result-list">
<ion-slide-box></ion-slide-box>
</ion-content>
In our controller, lets take those results and put them in a scope variable. I'm going to do some "theoretical" code here as I don't have a context as to what you are doing above.
angModule.controller("ExampleController", function($scope, $ionicSlideBoxDelegate) {
$scope.results = results;
});
Once we have the results in the scope, let's do an ng-repeat on the results.
<ion-content ng-controller="ExampleController" class="result-list">
<ion-slide-box>
<ion-slide ng-repeat="result in results">{{result}}</ion-slide>
</ion-slide-box>
</ion-content>
Again, this isn't complete code, more pointing you in the right direction.
I would suggest starting with some basics and fundamentals.
Suggest starting with these articles:
http://mcgivery.com/structure-of-an-ionic-app/
http://mcgivery.com/creating-views-with-ionic/
http://mcgivery.com/controllers-ionicangular/
And if you want even more learning resources:
http://mcgivery.com/100-ionic-framework-resources/
Based on instruction from this question, I have added the following code to my application within the config stage:
$provide.decorator('formDirective', function($delegate) {
var directive = $delegate[0];
directive.controller.prototype.inputs = {};
console.log(directive.controller);
return $delegate;
});
All I want to do is create another field and a few methods to the existing angular form object. All of that appears to be defined within the formDirective controller but when I prototype new fields and methods into that controller they are not available after my application is completed bootstrapping. Is there something I'm missing, is this even possible without modifying the source?
Thanks in advance!
EDIT Code Pen of Design Patterns Here
http://codepen.io/anon/pen/EadRBo
Thanks for your help. I did get this working and if your curious, this is why it was so important:
$provide.decorator('formDirective', function($delegate) {
var directive = $delegate[0];
directive.controller.prototype.$validate = function () {
var form = this;
var p;
for(p in form) {
if(form.hasOwnProperty(p) && p.indexOf('$') < 0) {
form[p].$setTouched();
}
}
};
A simple way to mark every element as touched causing the fields to be invalidated and error logic to kick in. I wanted this when a form was attempted to be submitted so that the user could see all the fields that were required. This also helps to keep my controllers slim without the extra overhead of an additional service.
I am using JQM and building a large lists of contacts from a webSQL database. Currently the process is painfully slow so I am trying to use a template to see how this affects performance.
I cannot figure out how to use a Jquery template with a WebSQL ResulSet.
This is the code so far:
function (tx, result)
{
var markup = '<li>${result.Name}</li>';
$.template("contactTemplate", markup);
$.tmpl("contactTemplate", /* What goes here? */).appendTo($list);
}
Ok, Jquery template expects an array. Therefore the following works:
var contacts = [];
for (i = 0; i < result.rows.length; i++)
{
contacts.push(result.rows.item(i));
}
var markup = '<li>${Name}</li>';
$.template("contactTemplate", markup);
$.tmpl("contactTemplate", contacts).appendTo($list);
This approach has very little impact on performance. Building the list is equally slow.