$watch function gives undefined - AngularJS - javascript

I am a very basic beginner in AngulerJS.
What i'm trying to do is that when a user clicks on a product, the types of that product come up, then they pick a type and the colors of that type come up. I've tried using the same system that gets the types to show but my colors keep coming up undefined.
<section class="colorDisplay">
<div class="mcolor" ng-repeat="color in shoColor">
<img ng-src="{{color.image}}"/></div>
</section>
script.js
$scope.prod = {"name":"Pens"};
$scope.typ = {"id":1};
$scope.$watch('prod.name',function(){
$http.get("products/"+$scope.prod.name+".json").success(function(data){
$scope.type = data;
});
$scope.$watch('typ.id',function(type){
$scope.shoColor = type[$scope.typ.id].colors;
});
})
JSON File
{
"types":[
{
"name":"laser",
"id":0,
"image":"d-u-b/pens/laser.png",
"colors":[
{
"color":"Black and Silver",
"image":"colors/blacksilver.png",
"prodimage":"d-u-b/pens/laser/blacksilver.png"
},
{
"color":"Red",
"image":"colors/red.png",
"prodimage":"d-u-b/pens/laser/red.png"
}
]
},
{
"name":"plain",
"id":1,
"image":"d-u-b/pens/plain.png",
"colors":[
{
"color":"Yellow",
"image":"colors/yellow.png",
"prodimage":"d-u-b/pens/plain/yellow.png"
},
{
"color":"Blue",
"image":"colors/blue.png",
"prodimage":"d-u-b/pens/plain/yellow.png"
},
{
"color":"Cyan",
"image":"colors/cyan.png",
"prodimage":"d-u-b/pens/plain/cyan.png"
},
{
"color":"Silver",
"image":"colors/silver.png",
"prodimage":"d-u-b/pens/plain/silver.png"
}
]
}
]
}
I'm trying to call the id number of a certain types colors, putting it into something like this: types[0].colors, where the 0 is the inserted id number.
No matter where I put the watch function or what I name it, it's either the "0" is undefined or "colors" is undefined.
What am I doing wrong this time?

change this
$scope.shoColor = type[$scope.typ.id].colors;
to
$scope.shoColor = $scope.type[type].colors;
and
$http.get("products/"+$scope.prod.name+".json").success(function(data){
$scope.type = data;
to
$http.get("products/"+$scope.prod.name+".json").success(function(response){
$scope.type = response.data;

Here is a working fiddle of what i think you are trying to achieve.
note: - i have hard coded the $scope.type data in order for it to work on jsfiddle.
i have used nested ng-repeats as it follows the same code structure as the json response.
Hope it helps,
D

Related

Getting json data for dropdown list using jquery not working

Looking for information on how to read a json from an api call we have to populate a dropdown list.
[
{
"name": "jira",
"description": "The default JIRA workflow."
},
{
"name": "Business Review and Build",
"description": "The default JIRA workflow starting point."
}
]
The json does not seem to have opening and closing { .. }. It looks basically like what I pasted in above. I guess it is like an anonymous array of two values, name, and description. It is retrieved via a url that has a go script running that outputs this json.
I tried to use jquery, but something like this does not display any options.
function populateWF() {
let dropdown = $('#projWF');
dropdown.empty();
dropdown.append('<option selected="true" disabled>Choose a workflow');
dropdown.prop('selectedIndex', 0);
const url = 'http://esjira01d.internal.company.com:8088/workflows';
$(document).ready(function() {
$.getJSON(url, function(obj) {
$(obj).each(function() {
dropdown.append($('<option>/option>')
.val(this.Name).html(this.Description));
}); #each
}); #getJSON
}); #ready
}
The option box does dispaly and it does say the mesage about Choose a workflow. It just seems to bomb at the actual getJSON.
It does not display anything in the drop down. If I go to the url, it shows what appears to be json. If I go to jlint and type in what I think it is returning, it says it is valid.
The data you get back is a normal Array of Objects encoded as JSON. To get the values, you can use a simple for-loop or the .forEach() function:
let obj = '[{"name":"jira","description":"The default JIRA workflow."},{"name":"Business Review and Build","description":"The default JIRA workflow starting point."}]';
obj = JSON.parse(obj);
let dropdown = $("#dropdown");
obj.forEach(function(e) {
let option = $('<option></option>');
option.val(e.name);
option.html(e.description);
dropdown.append(option);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="dropdown"></select>
function populateWF() {
let dropdown = $('#projWF');
dropdown.empty();
dropdown.append('<option selected="true" disabled>Choose a workflow');
dropdown.prop('selectedIndex', 0);
const url = 'http://esjira01d.internal.company.com:8088/workflows';
$(document).ready(function() {
$.getJSON(url, function(obj) {
obj.forEach(function(e) {
let option = $('<option></option>');
option.val(e.name);
option.html(e.description);
dropdown.append(option);
});
});
});
}
The result you received is an array instead of object. You can use .map() function to create the options.
var result = [
{
"name": "jira",
"description": "The default JIRA workflow."
},
{
"name": "Business Review and Build",
"description": "The default JIRA workflow starting point."
}
]
$(document).ready(function() {
result.map(function(item) {
$("select").append($('<option></option>').val(item.name).html(item.description));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select></select>

AngularJS - Get printed value from scope inside an attribute?

I'm currently working on an AngularJS project and I got stuck in this specific requirement.
We have a service that has all the data, DataFactoryService. Then, I have a controller called DataFactoryController that is making the magic and then plot it in the view.
<div ng-repeat = "list in collection">
{{list.name}}
...
</div>
Now, we have a requirement that pass multiple data into one element. I thought an "ng-repeat" would do, but we need to have it inside an element attribute.
The scenarios are:
At one of the pages, we have multiple lists with multiple data.
Each data has a unique code or ID that should be passed when we do an execution or button click.
There are instances that we're passing multiple data.
Something like this (if we have 3 items in a list or lists, so we're passing the 3 item codes of the list):
<a href = "#" class = "btn btn-primary" data-factory = "code1;code2;code3;">
Submit
</a>
<a href = "#" class = "btn btn-default" data-factory = "code1;code2;code3;">
Cancel
</a>
In the example above, code1,code2,code3 came from the list data. I tried several approach like "ng-repeat", "angular.each", array, "ng-model" but I got no success.
From all I've tried, I knew that "ng-model" is the most possible way to resolve my problem but I didn't know where to start. the code below didn't work though.
<span ng-model = "dataFactorySet.code">{{list.code}}</span>
{{dataFactorySet.code}}
The data is coming from the service, then being called in the controller, and being plot on the HTML page.
// Controller
$scope.list = dataFactoryService.getAllServices();
The data on the list are being loaded upon initialization and hoping to have the data tags initialized as well together with the list data.
The unique code(s) is/are part of the $scope.list.
// Sample JSON structure
[
{ // list level
name: 'My Docs',
debug: false,
contents: [ // list contents level
{
code: 'AHDV3128',
text: 'Directory of documents',
...
},
{
code: 'AHDV3155',
text: 'Directory of pictures',
...
},
],
....
},
{ // list level
name: 'My Features',
debug: false,
contents: [ // list contents level
{
code: 'AHGE5161',
text: 'Directory of documents',
...
},
{
code: 'AHGE1727',
text: 'Directory of pictures',
...
},
],
....
}
]
How can I do this?
PLUNKER -> http://plnkr.co/edit/Hb6bNi7hHbcFa9RtoaMU?p=preview
The solution for this particular problem could be writing 2 functions which will return the baseId and code with respect to the list in loop.
I would suggest to do it like below
Submit
Cancel
//inside your controller write the methods -
$scope.getDataFactory = function(list){
var factory = list.map( (a) => a.code );
factory = factory.join(";");
return factory;
}
$scope.getDataBase= function(list){
var base= list.map( (a) => a.baseId);
base= base.join(";");
return base;
}
Let me know if you see any issue in doing this. This will definitely solve your problem.
You don't really have to pass multiple data from UI if you are using Angular.
Two-way data binding is like blessing which is provided by Angular.
check your updated plunker here [http://plnkr.co/edit/mTzAIiMmiVzQfSkHGgoU?p=preview]1
What I have done here :
I assumed that there must be some unique id (I added Id in the list) in the list.
Pass that Id on click (ng-click) of Submit button.
You already have list in your controller and got the Id which item has been clicked, so you can easily fetch all the data of that Id from the list.
Hope this will help you... cheers.
So basing from Ashvin777's post. I came up with this solution in the Controller.
$scope.getFactoryData = function(list) {
var listData = list.contents;
listData = listData.map(function(i,j) {
return i.code;
});
return listData.join(';');
}

jQuery search in an object using a string

UPDATE
23 November 2016:
I was very close to the solution. Rory McCrossan has solved it for me, so I accepted his answer. BUT I changed the code for faster developing. I want to share this so you can use it to.
JSON langfile-v1.0.json
{
"nl": {
"text1":"Hallo Wereld!",
"text2":"voorbeeld.com",
"text3":"Ik hou van Stack Overflow"
},
"en":{
"text1":"Hello World!",
"text2":"example.com",
"text3":"I love Stack Overflow"
}
}
Javascript / jQuery script.js
//Creating an GLOBAL object
var languageObject;
//Get the language json file
$.get("langfile-v1.0.json", function(response){
languageObject = response; //Assign the response to the GLOBAL object
setLanguage(); //Calling the setLanguage() function
});
//Call this function to set the language
function setLanguage() {
$("lang").html(function() {
var userLang = navigator.language || navigator.userLanguage;
var langSupported = false; //Check if the user language is supported
$.each(languageObject, function(key) {
if (userLang == key) {
langSupported = true;
}
});
if (langSupported) {
//Users language is supported, use that language
return languageObject[userLang][$(this).html()];
} else {
//User language is NOT supported, use default language
return languageObject.en[$(this).html()];
}
});
}
HTML page.html
<lang>text1</lang> <br>
<lang>text2</lang> <br>
<lang>text3</lang>
Demo
You can check how this works on JSFiddle (with a slightly different code because I dont know how to inculde the langfile-v1.0.json file)
Click here for demo
OLD QUESTION POST:
I want to search in a object using a string.
Example:
JSON
{
"nl": {
"lang":"Nederlands",
"header-WelcomeText":"Welkom op de website",
"header-Sub1":"Hoofdpaneel"
},
"en": {
"lang":"English",
"header-WelcomeText":"Welcome on the website",
"header-Sub1":"Dashboard"
}
}
Javascript/jQuery
var output;
$.get("file.json", function(response){
output = response; //This is now a object in javascript
});
This all works, here what i want:
//The jQuery code
$('span .lang').text(output.nl.$(this).attr("data-lang"));
//The HTML code
<span class="lang" data-lang="header-Sub1"></span>
I know this will not work, but I know there will be a way to achief this.
To make this work there's a few changes you need to make.
when accessing the key of an object through a variable you need to use bracket notation.
to reference the element through the this keyword you need to run your code within it's scope. To do that you can pass a function to the text() method which returns the value you need from the object.
the .lang class is directly on the span, so you shouldn't have the space in your selector.
With all that in mind, this should work for you:
var output = {
"nl": {
"lang": "Nederlands",
"header-WelcomeText": "Welkom op de website",
"header-Sub1": "Hoofdpaneel"
},
"en": {
"lang": "English",
"header-WelcomeText": "Welcome on the website",
"header-Sub1": "Dashboard"
}
}
$('span.lang').text(function() {
return output.nl[$(this).data("lang")];
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="lang" data-lang="header-Sub1"></span>

Angular ng-options selected object

why is this not working?
HTML:
<div ng-controller="MyCtrl">
<select class="rp-admin-rooms-selected-select" name="teacherSelect" id="teacher"
ng-model="teacherSel"
ng-options="teacher.name for teacher in teachers "
>
</select>
{{teacherSel}}
</div>
JS:
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.teachers = [
{name:'Facundo', id:1},
{name:'Jorge', id:3},
{name:'Humberto', id:5},
{name:'David', id:7},
]
$scope.teacherSel = {name:'Facundo', id:1};
}
I would expect to be the selected element be Facundo
The thing is, I know that its possible to do this via teacherSel = id
and ng-options="teacher.name as teacher.id"...
But I have the object yet their, and I need the new object. not just the id.
jsfiddle:
http://jsfiddle.net/Lngv0r9k/
Michael Rose got it right. Another option would be force angular to do the comparison by value using a track by statement, as follows:
ng-options="teacher.name for teacher in teachers track by teacher.ID"
This works in angular 1.2 and after.
Updated fiddle: http://jsfiddle.net/Lngv0r9k/3/.
The issue is that the comparison for the selected entry is done via reference, not value. Since your $scope.teacherSel is a different object than the one inside the array - it will never be the selected one.
Therefore you need to find the selected entry inside the array and then use this as follows: $scope.teacherSel = $scope.teachers[indexOfSelectedEntry].
See at the bottom of your updated jsfiddle: http://jsfiddle.net/Lngv0r9k/1/
On your example you dont give a teacher object to the room.teacher , so the ng-options cant match anything to the ng-model.
As you see on the screen below, value=? means that it cant find correct value to match up.
you could try for example:
$scope.room = {
teacher: $scope.teachers[an item index];
};
OR
$scope.room = {
teacher: {
"ID": "1",
"name": "Adolf Ingobert",
"short": "AD",
"display": "Adolf I.",
"sectionFK": "2",
"invisible": "0"
};
};

On click How can I cycle through JSON one by one in AngularJS

Creating my first directive as an exercise in angular —making more or less a custom carousel to learn how directives work.
I've set up a Factory with some JSON data:
directiveApp.factory("Actors", function(){
var Actors = {};
Actors.detail = {
"1": {
"name": "Russel Brand",
"profession": "Actor",
"yoga": [
"Bikram",
"Hatha",
"Vinyasa"
]
},
"2": {
"name": "Aaron Bielefeldt",
"profession": "Ambassador",
"yoga": [
"Bikram",
"Hatha",
"Vinyasa"
]
},
"3": {
"name": "Adrienne Hengels",
"profession": "Ambassador",
"yoga": [
"Bikram",
"Hatha",
"Vinyasa"
]
}
};
return Actors;
});
And an actors controller:
function actorsCtrl($scope, Actors) {
$scope.actors = Actors;
}
And am using ng-repeat to display the model data:
<div ng-controller="actorsCtrl">
<div ng-repeat="actor in actors.detail">
<p>{{actor.name}} </p>
</div>
<div ng-click="next-actor">Next Actor</div>
</div>
1) How do I only display the actor's name in the first index of my angular model actors.detail?
2) How do I properly create a click event that will fetch the following index and replace the previous actor.name
User flow:
Russell Brand is Visible
click of next-actor ->Russell Brand's name is replaced with Aaron Bielefeldt
Since you only want the current user, the ng-repeat is not what you want to use, since that would be for each element in the data;
You would want to keep track of the index you are looking at in the scope, and increment that.
<div ng-controller="TestController">
{{data[current].name}}
<div ng-click="Next();"> NEXT! </div>
</div>
Where in the controller we also have these set up, where data is your actors:
$scope.current = 0;
$scope.Next = function() {
$scope.current = ($scope.current + 1) % $scope.data.length;
};
Here's a fiddle where it's done.
I would change my serivce to return a single actor and maintain the index in the controller.
something like this. This is an incomplete solution - you need to take care of cycle etc...

Categories