Apache cordova var not displayed in html - javascript

I have a problem with my application developped with angular & apache cordova on android.
On the first place I fetch the contact list from my smartphone and store it in a var : $scope.listecontacts
// alert('nb contacts '+contacts.length);
for (var i = 0; i < contacts_1.length; i++)
{
if(contacts_1[i].phoneNumbers != null && contacts_1[i].name != null && typeof contacts_1[i].phoneNumbers != 'undefined')
{
if($scope.numero_tel==0)
{
$scope.numero_tel = contacts_1[i].phoneNumbers[0].value;
}
$scope.listecontacts.push(contacts_1[i]);
}
}
And in a second time I try to display it in the html dom like this :
<div ng-repeat="t in listecontacts" >{{(t.name.formatted)}}</div>
When I launch my application it runs fine but when I go back in the home page and then go on the view that fetch the contact list, the DIV is not filled with the contact list.
I have checked the variable : $scope.listecontacts and it is not empty....
Has anyone ever meet this problem ?
Have you got any Idea ?
Thanks a lot !

I have tried to use a service this way :
app.factory('ContactService', function($window, $q, $rootScope){
var options = new ContactFindOptions();
options.filter = "";
options.multiple = true;
var filter = ["displayName", "name","phoneNumbers"];
// navigator.contacts.find(filter, onSuccess, onError, options);
return {
getContactList : function(onSuccess, onError){
navigator.contacts.find(filter,function(contacts){
$rootScope.$apply(function(){
onSuccess(contacts);
})
}, function(){
$rootScope.$apply(function(){
onError();
})
}, options)
}
}
})
And then in my controller :
$scope.get_contacts = function()
{
/*alert('get_contacts');*/
try
{
ContactService.getContactList(function(contacts)
{
But nothing chages, I check the variables with the console with via USB and Chrome and the array is fileld with thje value but the HTML doesn't displays the data.

Thanks for your help !
Actually my service was running fine I just had to change
this :
<option ng-repeat="t in listecontacts" value="{{(t.phoneNumbers[0].value)}}" >{{(t.name.formatted)}}</option>
to this
<option ng-repeat="t in listecontacts.liste_1" value="{{(t.phoneNumbers[0].value)}}" >{{(t.name.formatted)}}</option>
since I used an object instead of an array for "listecontacts"
$scope.listecontacts= {
liste_1: []
};

Related

AngularJS - run check against elements as they come back

I just followed this
JSFiddle example to create a little search box from an array object in my javascript. Now after some tweaking and research on search.object and filter:search:strict. Now that I have it filtering correctly, I modified a checkbox in the template that is checked upon loading the document and switched on or off based on a custom data attribute in the html that is updated by the json array.
How do I run this check once someone clears the search and the old items show back up again?
In the HTML I have this template
<div ng-repeat="o in objects | filter:search:strict | orderBy:'obj_name'" class="objectContainer">
<h3>{{o.obj_name}}</h3>
<label class="userToggleSwitch" >
<input class="userToggleInput" data-isactive="{{o.obj_isactive}}" type="checkbox">
<div class="slider round"></div>
</label>
</div>
In the JS
angular.element(document).ready(function(){
angular.module('searchApp',[])
.controller('searchCtrl', ['$scope','objHolder',function ($scope,objHolder) {
$scope.search = '';
$scope.objects = [];
$scope.objects = objHolder.getobjects();
}])
// fake service, substitute with your server call ($http)
.factory('objHolder',function(){
var objects = objList;
return {
getobjects : function(){
return objects;
}
};
});
});
The JS that modifies the items on document load is using jquery like this
$(document).ready(function(){
//console.log($('.userToggleInput'));
$.each($('.userToggleInput'), function(){
if($(this).data("isactive") == 1){$(this).attr('checked', true);}
if($(this).data("isactive") == 0){$(this).attr('checked', false);}
})
$('.userToggleInput').click(function(){
if ($(this).attr('checked') == undefined) {
// THIS IS WHERE WE WILL MAKE AN AJAX CALL TO A PHP CLASS
// TO REQUEST IF THE USER CAN BE TURNED ON - DUE TO LIC RESTRICTIONS
$(this).attr('checked',true);
} else {
$(this).attr('checked',false);
}
//console.log($(this).attr('checked'));
});
});
Created JS Fiddle to assist in Helping in this manner

ngRepeat not updating even though list is

I'm having a problem where despite a list being updated, ngRepeat does not display the information.
In the code below, the $scope.selectedImages array is being added to when images are selected using the file input. It is set up so that only unique files will be added to the list of selectedImages (no duplicates).
At the end of the function, scope.selectedImages prints the array with the new values, but in the view, ngRepeat does not add the new list items with the image names.
Other questions regarding this issue said that $scope.$apply should fix the problem, but for me it is not. Am I using it wrong or is there something else that I am misunderstanding.
EDIT: View 1 and View 2 are in separate HTML pages that both rely on the same controller.
View 1:
<input type="file" multiple accept="image/*" class="file-input" id="img-upload-btn" onchange="angular.element(this).scope().select(this)">
<md-button class="md-primary md-raised sidenav-btn" ng-click="proxy('img-upload-btn')">
Select <strong>Images</strong>
</md-button>
The proxy function allows the md-button to click the input.
View 2:
<div layout-padding flex ng-controller="upload-controller">
<ul>
<li ng-repeat="im in selectedImages">{{im.name}}</li>
</ul>
</div>
Controller:
$scope.selectedImages = [];
$scope.select = function(element) {
$scope.$apply(function(scope) {
var justFiles = $.map(element.files, function(val, key) {
return val;
}, true);
var fileEquality = function(f1, f2) {
if (f1.name != f2.name) return false;
if (f1.size != f2.size) return false;
if (f1.type != f2.type) return false;
if (f1.lastModified != f2.lastModified) return false;
return true;
}
// inefficient, find better way later
for (i in justFiles) {
var contains = false;
var file = justFiles[i];
for (i in scope.selectedImages) {
if (fileEquality(file, scope.selectedImages[i])) {
contains = true;
break;
}
}
if (!contains) scope.selectedImages.push(file);
}
console.log(scope.selectedImages);
});
};
Your input field template and controller template have to different scopes. Use $rootScope.selectedImages in your case.

Conflicts when working with scopes and controllers in AngularJS

I have a simple website that uses AngularJS with a NodeJS backend.
It has multiple pages, like a homepage, a login/register page, etc.
I'd like to implement a "Chat" page where you could send messages to other clients using socket.io. I already got that part working, using a local controller (by local, I mean active on a single page - the Chat page).
The problem is, I would like the chat system to be global (i.e. client can receive messages while being on the homepage, but they'll still only be displayed when going back on the Chat page).
I'm having an issue when setting the Chat controller global (active on all pages).
Here's how I'm including it:
<body ng-controller="AppCtrl"> <!-- include main controller -->
<div ng-include="'header.tpl.html'"></div>
<div ng-controller="ChatCtrl" class="page"> <!-- include global Chat controller -->
<div ng-view class="container"></div>
</div>
<div ng-include="'footer.tpl.html'"></div>
<!-- ...etc. -->
</body>
This works pretty well, but it seems like I can't access a value from my Chat page, though. Functions declared from the Chat controller can still be called, but the "$scope.message" value (which contains the message that's being typed) is always empty.
Here's my Chat controller (which is actually called TravelCtrl)
angular.module('base').controller('TravelCtrl', //['$scope', 'security',
function($rootScope, $scope, security, NgMap, $geolocation, socket){
$scope.messages = [];
// Socket listeners
// ================
socket.on('init', function (data) {
$scope.name = data.name;
$scope.users = data.users;
});
socket.on('send:message', function (message) {
$scope.messages.push(message);
});
socket.on('change:name', function (data) {
changeName(data.oldName, data.newName);
});
socket.on('user:join', function (data) {
$scope.messages.push({
user: 'Server',
text: 'User ' + data.name + ' has joined.'
});
$scope.users.push(data.name);
});
// add a message to the conversation when a user disconnects or leaves the room
socket.on('user:left', function (data) {
$scope.messages.push({
user: 'chatroom',
text: 'User ' + data.name + ' has left.'
});
var i, user;
for (i = 0; i < $scope.users.length; i++) {
user = $scope.users[i];
if (user === data.name) {
$scope.users.splice(i, 1);
break;
}
}
});
// Private helpers
// ===============
var changeName = function (oldName, newName) {
// rename user in list of users
var i;
for (i = 0; i < $scope.users.length; i++) {
if ($scope.users[i] === oldName) {
$scope.users[i] = newName;
}
}
$scope.messages.push({
user: 'Server',
text: 'User ' + oldName + ' has been authenticated as ' + newName + '.'
});
}
// Methods published to the scope
// ==============================
$scope.changeName = function () {
socket.emit('change:name', {
name: $scope.newName
}, function (result) {
if (!result) {
alert('There was an error changing your name');
} else {
changeName($scope.name, $scope.newName);
$scope.name = $scope.newName;
$scope.newName = '';
}
});
};
$scope.sendMessage = function () {
socket.emit('send:message', {
message: $scope.message
});
// add the message to our model locally
$scope.messages.push({
user: $scope.name,
text: $scope.message
});
// clear message box
$scope.message = '';
};
// ================
var init = function () {
$scope.newName = security.currentUser.username;
$scope.changeName();
}
if ($rootScope.hasLoaded() && $scope.name != security.currentUser.username) {
init();
} else {
$rootScope.$on('info-loaded', init);
}
}
//]
);
As well as the Chat page itself. The strange thing is that connected users and messages display correctly, but the controller can't seem to retrieve the typed message.
<div class='col'>
<h3>Users</h3>
<div class='overflowable'>
<p ng-repeat='user in users'>{{user}}</p>
</div>
</div>
<div class='col'>
<h3>Messages</h3>
<div class='overflowable'>
<p ng-repeat='message in messages' ng-class='{alert: message.user == "chatroom"}'>{{message.user}}: {{message.text}}</p>
</div>
</div>
<div class='clr'>
<form ng-submit='sendMessage()'>
Message: {{message}}<br/>
<input size='60', ng-model='message'/>
<input type='submit', value='Send as {{name}}'/>
</form>
</div>
When pressing the "Send" button, AngularJS successfully calls the sendMessage function, but retrieves the "message" value as an empty string, leading it to send an empty socket.io message.
I'm quite new to AngularJS, so my approach might be totally ridiculous. I'm convinced I'm missing something obvious but after re-reading the docs again, I really can't seem to find what.
Is this a proper way to organise an AngularJS app?
Thanks in advance for your help.
Having recently built a large scale Angular/Socket.IO application, I strongly suggest that you put all of your Socket implementation into a Service. This service will maintain all of your socket state, and allow you to inject it into any required controllers. This will allow you to have a main page for Chat, however still be able to display notifications, chat user information, etc in other areas of your application.
It's not about your problem, but I saw something I suspect to be wrong.
When you use another library with angularjs, you should use a bridge to it (angular-socket-io for example).
When you do an $http call with angular, it updates $scope correctly in the callback and the changes are seen in the view.
In your code:
socket.on('send:message', function (message) {
$scope.messages.push(message);
});
There is a problem: "socket" isn't a library included in angularjs, so when the callback is called, your "$scope" modification isn't correctly noticed to angularjs.
You have to do use $scope.$apply(function() { code here which modifies $scope });
Example:
socket.on('send:message', function (message) {
$scope.$apply(function() {
$scope.messages.push(message);
});
});
EDIT:
I would like the chat system to be global (i.e. client can receive messages while being on the homepage, but they'll still only be displayed when going back on the Chat page).
Either store the datas in a global variable, or use $rootScope which is the parent scope of all the $scope you use in the application.
EDIT 2:
In fact it should solve your problem ;)
Another things:
1) use $rootScope instead of $scope for global variables (or a global variable). In any $scope you will access $rootScope variables ($scope is a copy of either $rooScope or a parent $scope).
2) register socket.io only once. Currently, if you change pages, you will register new callbacks at EACH page change.

multiple expression if else within ng-repeat

<div ng-repeat="book in books">
<h3 class="title">{{book.title}}</h3>
</div>
I use above code to get and it work fine, but I also have a search function, which will also set $scope.books. Unfortuunetly I have no control over the api, the search callback returned different scheme, means to get the title of the books I have to navigate to somewhere else, like book.category.item.title.
so I'm thinking of doing something like this
<a href="#/{{book.title || book.category.item.title}}">
check if book.title isset, else display another expression. Is it correct?
Instead I would prefer using ng-href
<a ng-href="{{getTitle()}}">link</a>
In your controller, return the url by checking logic there.
angular.module("app",[])
.controller("MainCtrl", function($scope) {
$scope.book = {};
$scope.book.title = null;
$scope.book.category = {
item : {
title : "Rafi"
}
}
$scope.getTitle = function() {
return '#/'+ ($scope.book.title || $scope.book.category && $scope.book.category.item && $scope.book.category.item.title);
}
});
DEMO
if you don't want to use controller for some reason:
<a ng-href="{{'#/'+(book.title || book.category.item.title)}}">

Knockout foreach binding not working

I'm following John Papa's jumpstart course about SPA's and trying to display a list of customers loaded via ASP.NET Web API the knockout foreach binding is not working. The Web API is working fine, I've tested it on it's own and it is returning the correct JSON, because of that I won't post the code for it. The get method simply returns one array of objects, each with properties Name and Email. Although not a good practice, knockout is exposed globaly as ko by loading it before durandal.
I've coded the customers.js view model as follows
define(['services/dataservice'], function(ds) {
var initialized = false;
var customers = ko.observableArray();
var refresh = function() {
return dataservice.getCustomers(customers);
};
var activate = function() {
if (initialized) return;
initialized = true;
return refresh();
};
var customersVM = {
customers: customers,
activate: activate,
refresh: refresh
};
return customersVM;
});
The dataservice module I've coded as follows (I've not wrote bellow the function queryFailed because I know it's not being used)
define(['../model'], function (model) {
var getCustomers = function (customersObservable) {
customersObservable([]);
var options = {url: '/api/customers', type: 'GET', dataType: 'json'};
return $.ajax(options).then(querySucceeded).fail(queryFailed);
function querySucceeded(data) {
var customers = [];
data.forEach(function (item) {
var c = new model.Customer(item);
customers.push(c);
});
customersObservable(customers);
}
};
return {
getCustomers: getCustomers
};
});
Finaly the model module was built as follows:
define(function () {
var Customer = function (dto) {
return mapToObservable(dto);
};
var model = {
Customer: Customer
};
return model;
function mapToObservable(dto) {
var mapped = {};
for (prop in dto)
{
if (dto.hasOwnProperty(prop))
{
mapped[prop] = ko.observable(dto[prop]);
}
}
return mapped;
}
});
The view is then simply a list, it is simply:
<ul data-bind="foreach: customers">
<li data-bind="text: Name"></li>
</ul>
But this doesn't work. Any other binding works, and I've looked on the console window, and it seems the observable array is being filled correctly. The only problem is that this piece of code doesn't show anything on screen. I've reviewed many times the files but I can't seem to find the problem. What's wrong with this?
You can use the knockout.js context debugger chrome extension to help you debug your issue
https://chrome.google.com/webstore/detail/knockoutjs-context-debugg/oddcpmchholgcjgjdnfjmildmlielhof
Well, I just spent a lot of time on an local issue to realize that the ko HTML comment format, if used, should be like this:
<!-- ko foreach: arrecadacoes -->
and NOT like this:
<!-- ko: foreach: arrecadacoes -->
: is NOT used after ko...
I know this question is a little old but I thought I'd add my response in case someone else runs into the same issue I did.
I was using Knockout JS version 2.1.0 and it seems the only way I can get the data to display in a foreach loop was to use:
$data.property
so in the case of your example it would be
$data.Name
Hope this helps
I don't see anywhere in your code that you've called ko.applyBindings on your ViewModel.
KO has a known issue while using foreach in a non-container element like the one above <ul> so you have to use containerless control flow syntax.
e.g.
<ul>
<!-- ko foreach: customers-->
<li data-bind="text: Name"></li>
<!-- /ko -->
</ul>
Ref: http://knockoutjs.com/documentation/foreach-binding.html

Categories

Resources