Is there a way that I can get another object inside of an object using a input parameter from a function. I have two different $scope variables I want to set for names, one for zone managers and another for construction managers. In this example I have looped inside of each object to grab the names. I would need to do this process twice, so I am not interested in repeating this numerous number of times so I create a function. The problem is that whenever I use "value.functionInputValue" I get an error saying that it cannot read from undefined. Can someone help me know where I have gone wrong?
JavaScript:
$scope.zones = [{
zoneManagers: {
zone1: {
name: 'Name',
phone: 1111111
},
zone2: {
name: 'Name',
phone: 1111111
},
zone3: {
name: 'Name',
phone: 1111111
},
constructionManagers: {
zone1: {
name: 'Name',
phone: 1111111
},
zone2: {
name: 'Name',
phone: 1111111
},
zone3: {
name: 'Name',
phone: 1111111
}
}
}];
function namesFilter(zoneType)
{
var allZoneManagerNames = [];
angular.forEach($scope.zones, function(value, key)
{
var zoneTypeArray = Object.keys(value);
if ( zoneTypeArray.indexOf(zoneType) != 1 )
{
angular.forEach(value.zoneType, function(value2, key2)
{
if (allZoneManagerNames.indexOf(value2.name) == -1)
{
allZoneManagerNames.push(value2.name);
}
});
}
});
return allZoneManagerNames;
}
$scope.allZoneManagerNames = namesFilter("zoneManagers");
I think it should be value[zoneType] instead of value.zoneType since zoneType is the String that you pass as a parameter to the function.
Also, as #mhodges mentioned, it should be zoneTypeArray.indexOf(zoneType) != -1 instead of zoneTypeArray.indexOf(zoneType) != 1 but, in this case, you can simply do the check like this:
if(value[zoneType]){
...
}
Try this fiddle
Your $scope.zones variable is a little complicated, so you have to do a nested lookup of object fields.
The fiddle is a little simplified version! and I removed the array because I thought it is not needed. As there is only a big object left (instead of an array), a check should be like this zones[zoneType], instead of indexOf.
There are several things wrong with this code, both syntactically and logically, so I will try to point them out for you to see if it fixes your issues.
1) $scope.zones.zoneManagers is missing an ending } before $scope.zones.constructionManagers
2) You should be checking if (value[zoneType]) not if (...indexOf(zoneType) != 1)
3) You should be iterating over value[zoneType] not value.zoneType
Updated Code Should Look Like This:
var app = angular.module('app', []);
app.controller('mainCtrl', function($scope) {
$scope.zones = [{
zoneManagers: {
zone1: {
name: 'zoneName1',
phone: 1111111
},
zone2: {
name: 'zoneName2',
phone: 1111111
},
zone3: {
name: 'zoneName3',
phone: 1111111
}
},
constructionManagers: {
zone1: {
name: 'constName1',
phone: 1111111
},
zone2: {
name: 'constName2',
phone: 1111111
},
zone3: {
name: 'constName3',
phone: 1111111
}
}
}];
function namesFilter(zoneType) {
var allZoneManagerNames = [];
angular.forEach($scope.zones, function(value, key) {
if (value[zoneType]) {
angular.forEach(value[zoneType], function(value2, key2) {
if (allZoneManagerNames.indexOf(value2.name) === -1) {
allZoneManagerNames.push(value2.name);
}
});
}
});
return allZoneManagerNames;
}
console.log('Zone managers => ', namesFilter('zoneManagers'));
console.log('Construction managers => ', namesFilter('constructionManagers'));
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl">
</body>
</html>
I need to use image drop-down list from http://designwithpc.com/plugins/ddslick I am trying to set "selected" option after postback, but I get infinite loop of postbacks. Here is my code:
<form id="form1">
<select id="localeId" name="localeId"></select>
</form>
<script type="text/javascript">
//Dropdown plugin data
var ddData = [
{
text: "English",
value: "en",
selected: false,
description: "English",
imageSrc: "/assets/img/flags-icons/en-flag.png"
},
{
text: "Portuguese",
value: "pt",
selected: false,
description: "Portuguese",
imageSrc: "/assets/img/flags-icons/pt-flag.png"
},
{
text: "Russian",
value: "ru",
selected: false,
description: "Russian",
imageSrc: "/assets/img/flags-icons/ru-flag.png"
},
{
text: "Spanish",
value: "es",
selected: false,
description: "Spanish",
imageSrc: "/assets/img/flags-icons/es-flag.png"
}
];
$('#localeId').ddslick({
data: ddData,
defaultSelectedIndex: 3,
onSelected: function (data) {
if (data.selectedIndex > 0) {
$('#hidCflag').val(data.selectedData.value);
$.cookie('lang', document.getElementById("hidCflag").value, { expires: 365 });
form1.submit();
}
}
});
</script>
Could please help me to solve it?
Calling:
$( '#demoSetSelected' ).ddslick( 'select', { index: i } );
will also trigger the "onSelected()" function you defined causing an infinite loop.
I solved the same problem by modifying the source file (jquery.ddslick.js) and adding a flag to disable the call to onSelected():
Change the select function to:
methods.select = function (options) {
return this.each(function () {
if (options.index)
selectIndex($(this), options.index, options.disableTrigger);
});
}
Modify selectIndex function definition from:
function selectIndex(obj, index) {
to:
function selectIndex(obj, index, disableTrigger) {
At the very end of the function selectIndex(...), change from:
if (typeof settings.onSelected == 'function') {
settings.onSelected.call(this, pluginData);
}
to:
if ( !disableTrigger ) {
if (typeof settings.onSelected == 'function') {
settings.onSelected.call(this, pluginData);
}
}
Then use instead:
$( '#demoSetSelected' ).ddslick( 'select', { index: i, disableTrigger: true } );
As an aside: to select by value instead of index, check out the code mentioned in:
https://github.com/prashantchaudhary/ddslick/issues/78
https://github.com/lunrfarsde/ddslick
It's a fork of dd-slick with the description part removed. But added select by value.
You may use plugin's select method like
$('#demoSetSelected').ddslick('select', {index: i });
to select a particular index.
As per ddSlick demo#4 on their website(http://designwithpc.com/plugins/ddslick#demo)
I'm currently struggling with implementing a jQuery plugin to my site for tags (with custom data objects) with autocomplete. jQuery TextExt can be found here (http://textextjs.com/). I'm currently struggling with using custom data objects for each tag, which can only be chosen from what autocompletes. Based on this example (http://textextjs.com/manual/examples/tags-with-custom-data-objects.html) I'm trying to figure out how to return both "name" and "id" when a tag is chosen. Does anyone know how to achieve this or point me in the correct direction?
Perhaps the answer is somewhere in this example (http://textextjs.com/manual/examples/filter-with-suggestions.html)?
Here's what I have written, which isn't working (it only returns the name, I've tried adding 'item.id' to the functions but that didn't work for me either):
<script type="text/javascript">
jQuery(document).ready(function( $ ){
jQuery('#textarea').textext({
plugins: 'tags',
items: [
{ name: 'PHP', id: '1' },
{ name: 'Closure', id: '2' },
{ name: 'Java', id: '3' }
],
ext: {
itemManager: {
stringToItem: function(str)
{
return { name: str };
},
itemToString: function(item)
{
return item.name ;
},
compareItems: function(item1, item2)
{
return item1.name == item2.name;
}
}
}
});
})
</script>
Your itemManager code should probably look like this, you will need to store the suggestions in a custom array to look up their relevant ids in the stringToItem Method
itemManager: {
items: [], // A custom array that will be used to lookup id
stringToItem: function(str)
{
//Lookup id for the given str from our custom array
for (var i=0;i<this.items.length;i++)
if (this.items[i].name == str) {
id = this.items[i].id;
break;
}
return { name: str, id: id };
},
itemToString: function(item)
{
//Push items to our custom object
this.items.push(item);
return item.name ;
},
compareItems: function(item1, item2)
{
return item1.name == item2.name;
}
}
Is it possible to load fully custom set of data into select2? I mean I can customize the option text property, can I also do it for id?
The code below works perfect
var dummy = [
{ id: 1, Name: "opt1" },
{ id: 2, Name: "opt2" }
];
$("#myselect").select2({
data: { results: dummy, text: "Name" },
formatSelection: function (item) { return item.Name; },
formatResult: function (item) { return item.Name }
});
However, my data incoming has the id property in caps. It surely would be possible for me to rename these objects' properties iterating through the received data set, yet the amount of data is pretty large and I certainly do not want to slow this simple load down. I'd also love to have these object properties stay.
Long story short, my data is like
var dummy = [
{ ID: 1, Name: "opt1" },
{ ID: 2, Name: "opt2" }
];
Is it possible to define an alternate id key?
yes, there is an option called id
Function used to get the id from the choice object or a string
representing the key under which the id is stored.
$("#myselect").select2({
id: 'ID',
data: { results: dummy, text: "Name" },
formatSelection: function (item) { return item.Name; },
formatResult: function (item) { return item.Name }
});
I have a form that is suposed to help to user to choose a specific thing at the end, but as the user fills the first options, the others below change. Something like this:
Type:
{
t1:{
Number of X:{
1:{...}
2:{...}
}
Number of Y:{...}
}
t2:{
Number of X:{
100:{...}
200:{...}
}
Number of Y:{...}
}
}
The user has the field Type with the options t1 and t2, when they choose t1, the field "Number of X" will be filled with 1 and 2, if they choose t2, the field "Number of X" will be filled with 100 and 200, and so on. Some of the choices depend on more than one field, its not straight down dependency (something like, if the user chooses "Number of X" = 100 then Foo is "A", else, Foo can be "A", "B" or "C", but Foo is not bellow "Number of X").
I tried a really naive implementation where I would set up event listeners on every field and see their changes, but eventually the code started growing out of control and I have a bunch of $("#foo").change(function(){...}); and its not imediatly obvious that the field listening to this is bar and not fbar.
I also tried JSON (as the example above), but there's a lot of repetition, the deeper the tree grows and the number of possibilites increase, I have to write the same fields again and again. Sometimes choosing t1 will change an option directly even though its not directly bellow it, and even though it usually depends on another field entirely, and that's more repetition in JSON.
How do I approach this problem? Is there a readable solution? Too much code is not the problem, as long as one can look at the code and understand the dependencies and their effects.
A code example (kinda like my code right now):
HTML:
<select id="type">
<option value=1>a</option>
<option value=2>b</option>
</select>
<select id="numOfX">
</select>
<select id="numOfY">
</select>
js:
$("#type").change(function()
{
if($("#type").val() == 1)
{
$("#numOfX").append(new Option(1, "1", false, false));
$("#numOfX").append(new Option(2, "2", false, false));
}
else if($("#type").val() == 2)
{
$("#numOfX").append(new Option(1, "100", false, false));
$("#numOfX").append(new Option(2, "200", false, false));
}
});
$("#numOfX").change(function()
{
...
});
Update - Add example
Have you try backbone.js library? It will make the Javascript code more manageable by adding models & structures. There is a learning curve though but it is really great. Once you learn Backbone, you can make use of the Backbone Forms plugin which will help in the dropdown management. Below is the demo link & sample code:
Example 1
$(function() {
var cities = {
'UK': ['London', 'Manchester', 'Brighton', 'Bristol'],
'USA': ['London', 'Los Angeles', 'Austin', 'New York']
};
var subAreas = {
'London' : ['L1', 'L2', 'L3', 'L4'],
'Manchester' : ['M1', 'M2', 'M3', 'M4'],
'Brighton' : ['B1', 'B2', 'B3', 'B4'],
'Bristol' : ['BR1', 'BR2', 'BR3', 'BR4'],
'Los Angeles' : ['LA1', 'LA2', 'LA3', 'LA4'],
'Austin' : ['A1', 'A2', 'A3', 'A4'],
'New York' : ['NY1', 'NY2', 'NY3', 'NY4']
};
//The form
var form = new Backbone.Form({
schema: {
country: { type: 'Select', options: ['UK', 'USA'] },
city: { type: 'Select', options: cities.UK },
subArea: { type: 'Select', options: subAreas[cities.UK[0] ] }
}
}).render();
form.on('country:change', function(form, countryEditor) {
var country = countryEditor.getValue(),
newOptions = cities[country];
form.fields.city.editor.setOptions(newOptions);
var city = newOptions[0],
areaOptions = subAreas[city];
form.fields.subArea.editor.setOptions(areaOptions);
});
form.on('city:change', function(form, cityEditor) {
var city = cityEditor.getValue(),
newOptions = subAreas[city];
form.fields.subArea.editor.setOptions(newOptions);
});
//Add it to the page
$('body').append(form.el);
});
Example 2
$(function() {
var cities = {
'UK': ['London', 'Manchester', 'Brighton', 'Bristol'],
'USA': ['London', 'Los Angeles', 'Austin', 'New York']
};
var subAreas = {
'UK.London' : ['L1', 'L2'],
'USA.London' : ['L3', 'L4'],
'UK.Manchester' : ['M1', 'M2', 'M3', 'M4'],
'UK.Brighton' : ['B1', 'B2', 'B3', 'B4'],
'UK.Bristol' : ['BR1', 'BR2', 'BR3', 'BR4'],
'USA.Los Angeles' : ['LA1', 'LA2', 'LA3', 'LA4'],
'USA.Austin' : ['A1', 'A2', 'A3', 'A4'],
'USA.New York' : ['NY1', 'NY2', 'NY3', 'NY4']
};
var hashFunc = function(country, city){
return country + "." + city;
};
//The form
var form = new Backbone.Form({
schema: {
country: { type: 'Select', options: ['UK', 'USA'] },
city: { type: 'Select', options: cities.UK },
subArea: { type: 'Select', options: subAreas[ 'UK.London' ] }
}
}).render();
form.on('country:change', function(form, countryEditor) {
var country = countryEditor.getValue(),
newOptions = cities[country];
form.fields.city.editor.setOptions(newOptions);
var city = newOptions[0],
areaOptions = subAreas[hashFunc(country, city) ];
form.fields.subArea.editor.setOptions(areaOptions);
});
form.on('city:change', function(form, cityEditor) {
var city = cityEditor.getValue(),
newOptions = subAreas[hashFunc(form.getValue().country, city)];
form.fields.subArea.editor.setOptions(newOptions);
});
//Add it to the page
$('body').append(form.el);
});
As you also develop for mobile (probably Phonegap), you can also try ZeptoJS as an alternative for jQuery. It will improve the speed alot.
The task outlined is complex because of dependencies, so you must think of the ways to define your dependencies. Here is one way I would do it:
Define models which handle data.
Define dependencies.
Manage dependencies.
Below you can see a conceptual model how I see this all implemented (at the end of my answer I describe things which are not provided in this pseudo code):
//data/model structure for Type.
var type = {
//list all values.
values: [
{ id: 1, text: 't1', visible: true },
{ Id: 2, text: 't2', visible: true }
],
//evaluates visibility of item using dependencies.
//depends on nothing, so takes no arguments except item.
evaluate: function(item) {
return; //depends on nothing.
},
// this event fires when selected item changes.
onChange: event
};
//data/model structure for number of X.
var numberOfX = {
//list all values.
values: [
{ id: 1, text: '1', visible: true },
{ id: 2, text: '2', visible: true },
{ id: 3, text: '100', visible: true },
{ id: 4, text: '200', visible: true }
],
//evaluates visibility of item using dependencies.
//since numberOfX depends on Type, it takes type as second argument.
//it would take more arguments if it depended on other things too.
evaluate: function(item, type) {
// next line will fire onChange event.
item.visible =
( [1,2].indexOf(item.id) >=0 && type.id == 1 ) ||
( [3,4].indexOf(item.id) >=0 && type.id == 2 );
},
// this event fires when selected item changes.
onChange: event
};
//data/model structure for number of Y.
var numberOfY = { /* omitted. This is similar to the previous ones */ }
//numberOfX depends on Type.
//if it depended on more objects, then we would pass them as additional arguments.
register_dependency(numberOfX, type);
//numberOfY depends on Type.
register_dependency(numberOfY, type);
//... etc: define other dependencies.
Event mechanism is not there in JavaScript, but implementing one is not hard. You can use some framework for that as well.
register_dependency function builds a graph of dependencies simply by registering for events, as described below (managing dependencies):
When onChange event fires on any model, evaluate is called for each item in the dependency tree. For example, when type.onChange fires, we have numberOfX and numberOfY objects. Their values array is enumerated in loop and evaluate is called for each item (passing item and type as arguments).
Conclusion: although this code seems complex, still it's more self-descriptive and allows to have graph of dependencies between multiple objects on the page. Also, all the complexity lays on the toolkit/framework level, which could be easily re-used when implemented only once.
EDIT: Forgot to outline that you would need to have some mechanism to bind to this kind of model and show it on the page, which is also trivial. For example, have a look at knockout.js.