I can print the value in console but not in html view - javascript

I am new to angular js. I am trying to show data in dropdown but output is coming on console but not on html view.
html:-
<select ng-model="billing.billing" ng-options="billing in billAddress track by $index">
</select>
<p>{{billing.billing}}</p>
js file:
appServices.getBillAddress(userData.customerId).then(function (data){
if (data){
console.log(data);
$scope.addressToBill = data;
var billAddress=[];
//var billAddress=[];
if ($scope.addressToBill){
storeLocally.set('shipInfo', $scope.addressToBill);
for(var i=0;i<data.length;i++){
$scope.city = $scope.addressToBill[i].city;
$scope.state = $scope.addressToBill[i].state;
$scope.country = $scope.addressToBill[i].country;
$scope.billAddress = $scope.city +", "+ $scope.state +", "+ $scope.country;
console.log("billing address test: " +$scope.billAddress);
}
}
}
}
},
function (data) {
if (data.status == 500) {
$scope.addressError = "Oops! No Address Found!";
};
});
data has information:
[{city="fremont", country="USA", state="California"}]
I am getting error in console:
billing address test: fremont, California, USA
Error: [ngOptions:iexp] Expected expression in form of 'select (as label)? for (key,)?value in collection' but got 'billing in billAddress track by $index'.
I don't understand how to solve that select and ng-option error. If values are coming on console then Why it's not displaying in html dropdown. Please help me out.

First, your $scope.billAddress should be a collection, not a single string. Refactor your code as follows:
.then(function(data){
if (!data) {
// handling this case may vary; here I just clear the collection
$scope.billAddress = [];
return;
}
storeLocally.set('shipInfo', data);
$scope.billAddress = data.map(function(address) {
return {
billing: address.city + ', ' + address.state + ', ' + address.country
};
});
});
Second, you need to fix your ng-options syntax. One possible way:
<select ng-model="selectedBilling" ng-options="billing.billing for billing in billAddress track by $index">
<p ng-bind="selectedBilling.billing"></p>

It looks like you always set it to the last one in the list. Not sure if that is on purpose.. if so let me know.
But it sounds like you want to set billing address on each item and then use that as the label? If so set in your for loop data.billAddress = ... and use the below select.
<select ng-model="selectedBilling"
ng-options="billing as billing.billingAddress for billing in billAddress track by $index">
<p>{{selectedBilling}}</p>

This line won't work:
<p>{{billing.billing}}</p>
Cos the p is out of range from scope of select-> options
just an snippet to illustrate!
https://jsfiddle.net/alvarojoao/7wwdyymz/

Related

ng-repeat doesnt loop thru my array

Hey everybody can somebody please give me a clue what im doing wrong here?
I trying to build a wrapper where every element in my array gets a and a id
But when i loop thru my real array i only get a error with the text: Error: [ngRepeat:dupes] ...
With a fake array i made it works perfect.
MY HTML:
<div class="translaterBox">
<span ng-repeat="person in persons" id="{{person}}">
{{person + " "}}
</span>
<span ng-repeat="text in textWords" id="{{text}}">
{{text + " "}}
</span>
</div>
MY SCRIPT
var app = angular.module('splitScreenApp', []);
app.controller('splitCtrl', function ($scope, $http) {
$scope.translatetText = "Translate Here";
$http.get("getContent.php")
.then(function (response) {
var content = response.data.content;
$scope.content = content;
function splitContentToWords() {
var text;
for(var i = 0; i <= content.length;i++ ){
if(content[i].text){
var text = content[i].text;
}
return text.split(' ');
}
}
$scope.persons = [
'Jack',
'Jill',
'Tom',
'Harvey'
];
$scope.textWords = splitContentToWords();
console.log($scope.textWords);
console.log($scope.persons);
});
});
Thank you really much for your help
When you get an error about dupes from Angular, it is because there are duplicate keys. You can solve this by using track by as seen in the documentation.
Try changing your ng-repeat to:
<span ng-repeat="person in persons track by $index" id="{{person}}">
<span ng-repeat="text in textWords track by $index" id="{{text}}">

$$hashKey match and selected value for select menu

I am trying to set selected option for the select menu but its not working because data that I am sending to ng-model has different $$hashKey from data in the select menu and $$hashKey holding for values.
<select class="form-control" ng-model="selManga" ng-options="manga.seri for manga in mangalar">
<option value="">Manga Seçin</option>
</select>
<select ng-change="selPage = 0" ng-model="selChapter" ng-options="selManga.randomword.indexOf(chapter) as chapter.klasor for chapter in selManga.randomword">
<option value="">Bölüm</option>
</select>
<select ng-model="selPage" ng-options="selManga.randomword[selChapter].yol.indexOf(page) as selManga.randomword[selChapter].yol.indexOf(page) + 1 for page in selManga.randomword[selChapter].yol">
</select>
I google it to get around with this people says track by but I have to use as. So is there a another way to get around it?
Selected value for first select menu is working but second one is not working. Here is plunker.http://plnkr.co/edit/3V8JSF2AU01ZZNPfLECd?p=info
.controller('nbgCtrl',function ($scope, MMG, $stateParams) {
var milo = $stateParams.serix;
var musti = $stateParams.klasor;
MMG.adlar.success(function(loHemen) {
var i, miloMangaInArray;
for (i=0; i<loHemen.length; i++) {
if (loHemen[i].seri===milo) {
miloMangaInArray = loHemen[i];
break;
}
};
var a;
for (a=0; a<miloMangaInArray.randomword.length; a++) {
if(miloMangaInArray.randomword[a].klasor===musti) {
break;
}
}
$scope.mangalar = loHemen; //JSON Data
$scope.selManga = $scope.mangalar[i]; // First select menu's ng-model and its working.
$scope.selChapter = $scope.mangalar[i].randomword[a]; //Second select menu's ng-model and its not working due to no matching JSON data.
});
$scope.next = function (manga, chapter, page) {
var nextPage = page + 1;
if (angular.isDefined(manga.randomword[chapter].yol[nextPage])) {
$scope.selPage = nextPage;
} else if (angular.isDefined(manga.randomword[chapter + 1])) {
$scope.selChapter = chapter + 1;
$scope.selPage = 0;
}};
})
Dude here you go, a js fiddle for the solution
http://jsfiddle.net/yw248mfu/2/
the method I used here is indexOf to get the index of the page in the array for the last select only ,,
and this is not the best solution as it will have to apply index of every time the digest loop run ,,
I can think of a number of different solutions to this ,,
1- you can extract the id of the page from the name of the image itself
2- you can map the pages array to be a list of objects with the following schema
[{"index":1,"img":"00.jpg"},{"index":2,"img":"01.jpg"},{"index":3,"img":"02.jpg"}]
you can do the second option with this piece of code
pages.map(function(d,i){return {"index":i,"img":d};});
crouch74
I think you should embrace the AngularJS way of handling models and bindings. So, instead of keeping track of all the different indexes through your view code, you can simply let ng-select assign references to parts of your model (via ng-model). By changing the HTML and controller slightly, you can simplify some of the code, and it will actually work, too.
First, make a shared $scope.model = {…} object available on the $scope. Then, change the HTML to
<select ng-model="model.selManga" ng-options="manga.seri for manga in mangalar">
<option value="">Manga Seçin</option>
</select>
<select ng-model="model.selChapter" ng-options="chapter.klasor for chapter in model.selManga.randomword" ng-change="model.selPage = model.selChapter.yol[0]">
<option value="">Bölüm</option>
</select>
<select ng-model="model.selPage" ng-options="page as model.selChapter.yol.indexOf(page) + 1 for page in model.selChapter.yol">
</select>
<img class="picture" ng-src="http://baskimerkeziankara.com/{{model.selPage}}" ng-click="next(model.selPage)">
After that, change the controller is changed accordingly:
.controller('nbgCtrl', function($scope, MMG, $stateParams) {
var model = {
selManga: undefined,
selChapter: undefined,
selPage: undefined
};
$scope.model = model;
MMG.adlar.success(function _init(loHemen) {
for (var i = 0; i < loHemen.length; i++) {
if (loHemen[i].seri === $stateParams.serix) {
model.selManga = loHemen[i];
break;
}
}
for (var a = 0; a < model.selManga.randomword.length; a++) {
if (model.selManga.randomword[a].klasor === $stateParams.klasor) {
model.selChapter = model.selManga.randomword[a];
break;
}
}
model.selPage = model.selChapter.yol[0];
$scope.mangalar = loHemen;
});
$scope.next = function _next(page) {
var pageIndex = model.selChapter.yol.indexOf(page);
if (angular.isDefined(model.selChapter.yol[pageIndex + 1])) {
model.selPage = model.selChapter.yol[pageIndex + 1];
} else {
var chapterIndex = model.selManga.randomword.indexOf(model.selChapter);
if (angular.isDefined(model.selManga.randomword[chapterIndex])) {
pageIndex = 0;
model.selChapter = model.selManga.randomword[chapterIndex + 1];
model.selPage = model.selChapter.yol[pageIndex];
}
}
console.log('manga', model.selManga.seri,
'chapter', model.selChapter.klasor,
'selPage', pageIndex + 1);
};
})
I've created a forked Plunker that shows how this works (and this solution actually works): http://plnkr.co/edit/2aqCUAFUwwXuGQHpuooj

Update exiting element ng-repeat list in angularjs?

I made task table through the ng-repeat, Each task in table can can be modify. Task table will have to updated with updated task. So for this we need to access particular ng-repeat element. I want to know how to access particular ng-repeat element and update this with new task ng-click=editTask().
Please see $scope.editTask, Here I want to update inside $http.put(uri, data).
Workflow:
ng-click=beginTask(task) opens dialog, In dialog there is ng-click=editTask(), which will modify the task through $http.put...
Please see DEMO
<tr ng-repeat="task in tasks">
<td>{{task.title}}</td>
<td>{{task.description}}</td>
<td>
<a class="btn" data-toggle="modal" ng-click="beginEdit(task)">Edit</a>
</td>
</tr>
Angularjs code
$scope.beginEdit=function(task){
$scope.title = task.title;
$scope.description=task.description;
$scope.done=task.done;
$scope.uri=task.uri;
$scope.index=$scope.tasks.indexOf(task);
$('#edit').modal('show');
};
$scope.editTask = function() {
title=$scope.title;
description=$scope.description;
done=$scope.done;
uri=$scope.uri;
$('#edit').modal('hide');
var i=$scope.index;
var data={title: title, description: description, done: done };
$http.put(uri, data)
.success(function(){
alert("Success");
});
};
Please check this - : http://plnkr.co/edit/lVkWEsAGVLTY7mGfHP5N?p=preview
Add
$scope.tasks[$scope.index] = data;
In editTask
$scope.editTask = function(obj) {
alert($scope.title);
title = $scope.title;
description = $scope.description;
done = $scope.done;
uri = $scope.uri;
$('#edit').modal('hide');
var i = $scope.index;
var data = {
title: title,
description: description,
done: done
};
alert("uri" + uri);
alert(data.title);
$scope.tasks[$scope.index] = data; // For updating value
$http.put(uri, data)
.success(function() {
//tasks[i].uri(data.uri);
alert("Success");
});
};

Knockout Nested Bindings--Visible in DOM but won't display

I've got an issue where my viewmodel has an observable object that contains observable properties. When I try to access those properties they don't display. I can, however, see that all the properties with values are visible in the DOM using the Knockout chrome extension.
My code looks like:
viewmodel:
self.device=ko.observable();
self.device(querydevice.query({"url": self.url, "ref":self.ref}));
query code:
define(['jquery','knockout','hsd'], function ($,ko, device) {
return{
query:function (params) {
var hsdevice=ko.observable();
self.url=params.url;
self.ref=params.ref;
var controlData = $.getJSON(self.url + "/JSON?request=getcontrol&ref=" + self.ref);
var statusData = $.getJSON(self.url + "/JSON?request=getstatus&ref=" + self.ref);
$.when(controlData, statusData).done(function (_cdata, _sdata) {
var data = $.extend(_cdata[0], _sdata[0]);
hsdevice(new device(data));
});
return hsdevice;
}};
});
device object:
define(['knockout'], function (ko) {
return function device (data){
var self=this;
self.deviceName = ko.observable(data.Devices[0].name);
self.value = ko.observable(data.Devices[0].value);
self.status =ko.observable(data.Devices[0].status);
self.controlPairs = ko.observableArray();
ko.utils.arrayPushAll(self.controlPairs, data.ControlPairs);
};
});
This is what I see being returned:
" device": Object
controlPairs: Array[2]
deviceName: "Garage Hall Light"
status: "Off"
value: 0
In my HTML I have this:
<span class="tile-title align-" data-bind="with: device.deviceName"></span>
I've also tried using data-bind:"text: device().deviceName", but that doesn't work either. Nothing displays. I can however access over observable properties that are on the viewmodel. The only difference is that they're single level properties with no sub-binding. So I am able to see something like self.test("test") in my html but not my self.device with the nested databinds.
Any ideas what I'm doing wrong?
Thanks!
It looks like you are using jquery promises. what you need to do is return the $.when
something like
define(['jquery','knockout','hsd'], function ($,ko, device) {
return{
query:function (params) {
self.url=params.url;
self.ref=params.ref;
var controlData = $.getJSON(self.url + "/JSON?request=getcontrol&ref=" + self.ref);
var statusData = $.getJSON(self.url + "/JSON?request=getstatus&ref=" + self.ref);
return $.when(controlData, statusData).done(function (_cdata, _sdata) {
var data = $.extend(_cdata[0], _sdata[0]);
return new device(data);
});
}};
});
then you end up with something like this.
querydevice.query({"url": self.url, "ref":self.ref})
.when(function(data){
self.device(data);
return true;
});
Thanks to Nathan for his code contribution. I was finally able to access my nested properties in the html by using:
<!-- ko with: device -->
<!-- /ko -->
and THEN data-bind to the property I needed.

Bootstrap Multiselect update option list on flow

I use bootstrap multi-select and I want to update options on flow with ajax
To populate on init my multiselect I do
<select name="model" class="multiselect" multiple="multiple">
<? foreach ($sel_models as $mod) { ?>
<option value="<?= $mod ?>" <?= ($mod == $params['model']) ? 'selected' : '' ?>><?= $mod ?></option>
<? } ?>
</select>
then on event I would like to update my option list with the following ajax
I was trying to use the rebuild method but won't fire the drop-down after creation
$.ajax({
type: 'post',
url: "helper/ajax_search.php",
data: {models: decodeURIComponent(brands)},
dataType: 'json',
success: function(data) {
$('select.multiselect').empty();
$('select.multiselect').append(
$('<option></option>')
.text('alle')
.val('alle')
);
$.each(data, function(index, html) {
$('select.multiselect').append(
$('<option></option>')
.text(html.name)
.val(html.name)
);
});
$('.multiselect').multiselect('rebuild')
},
error: function(error) {
console.log("Error:");
console.log(error);
}
});
With firebug I can see that the list is generated but on select won't show up
In the doc I can read :
.multiselect('setOptions', options)
Used to change configuration after initializing the multiselect. This may be useful in combination with .multiselect('rebuild').
Maybe you can't change your widget data by your initial way. In a correct way you should use setOptions method.
Else : With your way, maybe should you think about destroy your widget .multiselect('destroy') and create it again after.
Update after comment :
In the doc : ( you've linked )
Provides data for building the select's options the following way:
var data = [
{label: "ACNP", value: "ACNP"},
{label: "test", value: "test"}
];
$("#multiselect").multiselect('dataprovider', data);
So :
When you get data from your ajax call, you have to create an array of objects ( it's the options in the select you want to have ) with the format like
var data =
[
{label: 'option1Label', value: 'option1Value'},
{label: 'option2Label', value: 'option2Value'},
...
]
When your objects array is created, then you just have to call the method
$("#multiselect").multiselect('dataprovider', data);
Where data is your array of objects.
I hope I'm clear :/
As an alternative to multiselect('dataprovider', data) you can build the list with jquery append exactly the way you did in your question. The only change you need to make is to delay the rebuild until after the ajax request is complete.
var buildDrivers = $.getJSON('resources/orders/drivers.json', function(data) {
$.each(data, function(i, driver) {
$('#toolbar select[name="drivers"]').append('<option>'+driver+'</option>');
});
});
buildDrivers.complete(function() {
$('.multiselect').multiselect('rebuild');
});
see http://api.jquery.com/jquery.getjson/ for documentation
I've been added the functionality of updating options after filtering and getting them from the server side. This solution relays on the concept of injecting new options, destroying the select and initializing it again.
I took into account:
Considering the existing selected options, which must stay.
Removing duplicate options (might be as a conflict from which that already selected and the new that came from the server).
Keeping the options tray open after the update.
Reassign the previous text in the search text box & focusing it.
Just add the 'updateOptions' as a function after the 'refresh' function along with the two helper functions as follows:
updateOptions: function (options) {
var select = this.$select;
options += this.getSelectedOptionsString();
var selectedIds = select.val(),
btnGroup = select.next('.btn-group'),
searchInput = btnGroup.find('.multiselect-search'),
inputVal = searchInput.val();
options = this.removeOptionsDuplications(options);
if (!options) {
options = '<option disabled></option>';
}
// 1) Replacing the options with new & already selected options
select.html(options);
// 2) Destroyng the select
select.multiselect('destroy');
// 3) Reselecting the previously selected values
if (selectedIds) {
select.val(selectedIds);
}
// 4) Initialize the select again after destroying it
select.multiselect(this.options);
btnGroup = select.next('.btn-group');
searchInput = btnGroup.find('.multiselect-search');
// 5) Keep the tray options open
btnGroup.addClass('open');
// 6) Setting the search input again & focusing it
searchInput.val(inputVal);
searchInput.focus();
},
getSelectedOptionsString: function () { // Helper
var result = '',
select = this.$select,
options = select.find('option:selected');
if (options && options.length) {
$.each(options, function (index, value) {
if (value) {
result += value.outerHTML;
}
});
}
return result;
},
removeOptionsDuplications: function (options) { // Helper
var result = '',
ids = new Object();
if (options && options.length) {
options = $(options);
$.each(options, function (index, value) {
var option = $(value),
optionId = option.attr('value');
if (optionId) {
if (!ids[optionId]) {
result += option[0].outerHTML;
ids[optionId] = true;
}
}
});
}
return result;
},
Demo:
State:
"Option 1"
$('#select').multiselect('updateOptions', '<option value="2">Option 2</option>');
State:
"Option 2"
"Option 1"
I think this is an easier way to add options on the fly (using ajax or any other listener) to an existing Bootstrap MultiSelect.
Following is a simplified example to add options:
function addOptionToMultiSelect(multiselectSelector, value, selected) {
var data = [];
$(multiselectSelector + ' option').each(function(){
var value = $(this)[0].value;
var selected = $(this)[0].selected;
data.push({label: value, value: value, selected: selected});
});
// Add the new item
data.push({label: value, value: value, selected: selected});
$(multiselectSelector).multiselect('dataprovider', data);
}
For simplicity, I have assumed both the label and value are the same in an option. Note that the already selected options are taken care of by reading the selected attribute from the existing options. You can make it more sophisticated by tracking the disabled and other attributes.
Sample:
addOptionToMultiSelect('#multiselect-example', 'new-option', true);

Categories