Dropdown options not populating with JSON - javascript

I am trying to take some JSON and fill the options of dropdown menu.I am using Materialize a front end css framework which I think may be the root of the problem here. I say this because if I do it with the default browser dropdown it works exactly as I expect, but not with their (Materialize's) dropdown. I do have to init the dropdown when the page loads, so maybe the solution is I have to re-init it, but I do not know how to do that.
This is the html where the form is:
<div class="row" style="margin-bottom:0px">
<form class="col s12"> <div class="row">
<div class="input-field col s12">
<select ng-options="Country for Country in countries" ng-model="selCountry" ng-change="onChange('sel')">
<option value="" disabled>Select Indicator</option>
</select>
<label>Indicators</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input id="search_targets" type="text" ng-model="searchText" ng-change="onChange('txt')">
<label for="search_targets">Search Targets</label>
</div>
</div>
<div class="col s12" style="
padding-left: 11.250px;
padding-right: 11.250px;
margin top:5vh;
">
<table>
<thead>
<tr>
<th data-field="id">Name</th>
<th data-field="name">Score</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="item in records | orderBy:'Name':reverse | filter:selCountry | filter:searchText | limitTo: 10">
<td>{{item.Name}}</td>
<td>{{item.Country}}</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
This is all of the JS I have, including the initialization of the dropdown # the bottom:
(function($){
angular.module('myapp', [])
.controller('MainCtrl', function($scope, $http) {
var records;
$scope.selCountry = '';
$scope.searchText = '';
$http.get('http://www.w3schools.com/angular/customers.php').success(function(dt) {
//window.alert(angular.toJson(dt));
$scope.countries = [];
$scope.records = dt.records;
dt.records.forEach(function(o) {
var c = o.Country;
if ($scope.countries.indexOf(c) == -1)
$scope.countries.push(c);
});
$scope.total = $scope.countries.length;
ready();
});
$scope.matches = 0;
$scope.onChange = function(src) {
if (src === 'txt') {
$scope.selCountry = '';
$scope.search = $scope.searchText;
} else {
$scope.searchText = '';
$scope.search = $scope.selCountry;
}
search($scope.search);
};
});
$(function(){
$('.button-collapse').sideNav();
}); // end of document ready
$('.datepicker').pickadate({
selectMonths: true, // Creates a dropdown to control month
selectYears: 15 // Creates a dropdown of 15 years to control year
});
$(document).ready(function(){
$('ul.tabs').tabs('select_tab', 'tab_id');
$('select').material_select();
});
})(jQuery); // end of jQuery name space
If the solution is to re-initialize the dropdown after the JSON is pulled, I am not sure how to do so.

In the success callback, you must use $scope.$apply to apply scope modifications since $http is asynchronous. Then did you check what dt contains with console.log(dt)?

You can reinitialize or update your select element by simply calling (as the same way you init)
$('select').material_select();
Note: You should call this statement on your success callback.

Related

Dynamically generating select tags with dynamic options and add generate another select tag when an option is selected

As the title of the question. This is what I want to achieve. I have a webpage when the web page loads it loads options (from db) to the static select tag. So there's only 1 static select tag. And when the user select an option from that 1st tag another select tag with the same options should be generated below the 1st tag and also data table containing data according to selected option should be appear in a table. And when the user select an option from the newly generated select tag then another tag with the same options should be generated below the select tag and same with the data table. Like this it goes on.
I'm using laravel as backend. And did all the data retrieving via ajax get.
So far I was able to get the options from the db and dynamically add the options to select tags also get the data table according to selected option in the static tag.
But it didn't generate another tag after selecting an option from the 2nd select tag.
This is the static select tag code
<div class="row" id="routeDetailsRow">
<div class="col-md-3">
<div class="panel panel-bordered">
<div class="panel-body">
<div class="form-group row">
<label for="routeCode" class="col-sm-4 col-form-label">Date</label>
<div class="col-sm-8">
<input type="date" name="date" id="date" class="col-sm-8 form-control">
</div>
</div>
<div class="form-group row">
<label for="routeCode" class="col-sm-4 col-form-label">Route Code</label>
<div class="col-sm-8">
<select id="selectRoute" class="form-control">
</select>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-9">
<div class="panel panel-bordered">
<div class="panel-body">
<div id="routePlanTablediv">
<div id="noResultsDiv"><h4 id="noResultDivText"></h4></div>
<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
<table class="table table-bordered table-hover no-display" id="routePlanTable">
<thead>
<tr>
<th>Invoice No</th>
<th>Route Code</th>
<th>Customer Code</th>
<th>Routeplan Code</th>
<th>Status</th>
</tr>
</thead>
<tbody id="routePlanTableBody">
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
I'm passing the static select tag's id to load the options to the tag like this
$(document).ready(function() {
getUserData('selectRoute'); //this is the function and works as expected
$("#enterVehicleNo").on("keydown", function(event) {
$("#selectRoute").removeAttr('disabled');
});
});
This is how I get the data table with the static select tag and generate new select tag.
$(document).on('change', '#selectRoute', function() {
var selector_id = '#selectRoute';
var table_id = '#routePlanTable';
getSelectedRouteDetails(selector_id, table_id); //data table function
addRows(); //add new select tag function
});
getSelectedRouteDetails() function
function getSelectedRouteDetails(selector_id, table_id) {
var selectedRC = document.getElementById(selector_id).value;
var result = $('#' +selector_id).val().split('|');
$('#routeplanno').text(result[1]);
console.log(selectedRC);
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
},
complete: function() {
$('.lds-ellipsis').hide();
}
});
$.ajax({
url: 'retreiveRouteData',
data: {
RouteCode: result[0]
},
dataType: 'json',
method: 'get',
success: function(result) {
if (result) {
$(table_id).removeClass('no-display');
$(table_id + ' tbody').html(result);
$('#noResultDivText').hide();
} else {
$(table_id).addClass('no-display');
$('#noResultDivText').text('No results were found !');
}
}
});
}
I'm using mustache.js to generate a new select tag and the template is same as the static select tag with dynamic ids followed by count (selectRoute_1)
addRows() function
var template = $("#form_rows_tpl").html(),
$target = $("#generate_new_route"),
$btnRemove = $("button.remove"),
$msg = $('.msg'),
max = 10,
count = 1,
inputRow = [];
$btnRemove.click(function(e) {
e.preventDefault();
removeRows();
});
var sId,tableID;
function addRows() {
if (count <= max) {
inputRow = {
count: count
}
tableID = 'routePlanTable_1'; //hardcoded the table id and select tag id for testing purpose
sId = 'selectRoute_1';
var html = Mustache.to_html(template, inputRow);
$target.append(html);
count++;
var routecode_selector = document.getElementsByClassName('route-code-selector');
console.log(routecode_selector.length);
for (var i = 0; i < routecode_selector.length; i++) {
var select_id = routecode_selector[i].getAttribute('id');
$('#'+select_id).removeAttr('disabled');
newRoute(select_id,tableID);
}
} else {
$msg.text('too many fields!');
}
}
function removeRows() {
$target.find('.row').last().remove();
$msg.text('');
if (count <= 1) {
count = 1;
} else {
count--;
}
}
What I don't understand is how to get the dynamically generated select tags ids' and pass them to addRows() function. And I know this is kind of a messy code and if some of you have any suggestions and if there are other better ways to achieve this please comment them below.
After hours of trying I was able to solved my issue with adding a button to generate a new select tag instead of generating a select tag after user select an option. And functions should be called in right time and in right functions.

How to Pass id and name from the first form, and Show only the name in second form in angularjs

I Have two forms.In these forms am getting input from the first form and show that in the second form, Which means if the user selected the currency from the dropdown, i need to pass id and the the currency name. But show only the currency name in the second form. I tried one method (dont know whether it is correct or not) it is showing the id only. am new to angular. is there anyway to solve this?
HTML
<div class="row text-center" ng-show="firstform">
<form name="validation">
<label>Currency</label>
<select ng-model="CurrencyId" ng-selected="CurrencyId" class="form-control" id="CurrencyId">
<option ng:repeat="CurrencyId in currencyList" ng-selected="selectedCurrencyType == CurrencyId.id" value={{CurrencyId.currencyId}}>{{CurrencyId.name}}</option>
</select>
<label>Grade</label>
<select ng-model="GradeId" ng-selected="GradeId" class="form-control" id="GradeId">
<option ng:repeat="GradeId in RaceGradeList" ng-selected="selectedGrade == GradeId.id" value={{GradeId.id}}>{{GradeId.gradeName}}</option>
</select>
<button type="submit"value="add" ng-click="savedetails()" />
</form>
</div>
<div class="row text-center" ng-show="secondform">
<form name="thirdform">
<ul >
<li><p>Currency:{{CurrencyId}}</p> </li>
<li><p>Grade:{{GradeId}}</p> </li>
</ul>
</form>
</div>
angular controller
$scope.savedetails = function () {
$scope.firstform= false;
$scope.secondform = true;
}
This is the most simplest solution that you can go for. Instead of having the value={{CurrencyId.currencyId}} set it as value={{CurrencyId.name}} for the options in the dropdown and you are good to go. Below is the demo for the same. But if you want to save currencyId as the value then you will have to iterate over the array and find the name based on the selected currencyId and then show that in the view.
UPDATE
Updated the code to have the currencyId being stored as the selected value and then based on that showing the name in the view.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.currencyList = [{
currencyId: 1,
name: "INR"
},
{
currencyId: 2,
name: "$"
},
{
currencyId: 3,
name: "#"
}
];
$scope.currencyChanged = function() {
var selectedCurrency;
for (var i = 0; i < $scope.currencyList.length; i++) {
var thisCurr = $scope.currencyList[i];
if ($scope.CurrencyId == thisCurr.currencyId)
selectedCurrency = thisCurr.name;
}
return selectedCurrency;
}
$scope.firstform = true;
$scope.savedetails = function() {
$scope.firstform = false;
$scope.secondform = true;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<div class="row text-center" ng-show="firstform">
<form name="validation">
<label>Currency</label>
<select ng-model="CurrencyId" ng-selected="CurrencyId" class="form-control" id="CurrencyId">
<option ng:repeat="CurrencyId in currencyList" ng-selected="CurrencyId == CurrencyId.currencyId" value={{CurrencyId.currencyId}}>{{CurrencyId.name}}</option>
</select>
<button type="button" value="add" ng-click="savedetails()">Save Details</button>
</form>
</div>
<div class="row text-center" ng-show="secondform">
<form name="thirdform">
<ul>
<li>
<p>Currency:{{currencyChanged()}}</p>
</li>
</ul>
</form>
</div>
</body>
Hope it helps :)
You can use ng-options , its very flexiable where we can display one value and select either entire object or any specific property.
Please check below plunker , hope it meets your requirement
https://plnkr.co/edit/JQjmAwk62R8rfAlTZ696?p=preview
<select ng-model="CurrencyId" ng-options="currency.id for currency in currencyList" class="form-control" id="CurrencyId" >
</select>
For more details on ng-options , go through below video
https://www.youtube.com/watch?v=vqx3zCy4d3I
try
<li><p>Currency:{{CurrencyId.name}</p> </li>

Angular $scope not passing results to parent controller on update

In my App I have an $http.get() request that stores data into the array $scope.requirements and a boolean into $scope.requirementsFulfilled.
I have a directive using the same controller as the page. They both do an ng-repeat on the $scope.requirements. When the requirementsFulfilled is false only the directive version shows, when true only the containing page.
The problem is when I envoke $http.get() after the first time the results are only being stored in the directive version. How do I make sure this information is bound to both?
Within the controller...
$scope.requirementsFulfilled;
$scope.requirements = [];
$scope.getRequirements = function(url) {
$http.get(url)
.then(function(res){
$scope.requirements = res.data.requirements;
$scope.setFulfilled( res.data.fulfilled );
});
};
$scope.submitRequirementScan = function() {
if ($scope.checkRequirement() ) {
$scope.getRequirements('tempjson/requiredPartsFulfilled.json');
}
};
$scope.setFulfilled = function( inputFulfilled ) {
$scope.requirementsFulfilled = inputFulfilled;
};
$scope.getRequirements('tempjson/requiredParts.json');
The page gets the requirements and populates the page. Then the user takes actions which fires off checkRequirement() and then fetches the new json if true. From this point only the directive is updating.
I believe that a child scope is being created for the directive, but I am not certain exactly what is happening. Here is the entirity of the directive info.
.directive("operationRequirements", function () {
return {
restrict: "E",
templateUrl: "requirements/requirements.html"
};
});
What is going on with it?
edit - Html for the directive
<div class="col-md-6 col-md-offset-3">
<h5>Scan Requirements</h5>
<form ng-submit="submitRequirementScan()" ng-controller="operationCtrl">
<label> <div class="glyphicon glyphicon-barcode ng-hide" ng-hide="requirement.scanned"></div>
<input type="text" ng-model="text" name="text" placeholder="Scan Barcode" autofocus /></label>
<input type="submit" id="submit" value="Submit Scan" class="btn" />
<table class="table table-hover">
<tr ng-repeat="requirement in requirements | filter : unScannedFilter">
<td>{{$index + 1 }}</td>
<td>
<div class="glyphicon glyphicon-barcode ng-hide" ng-hide="requirement.scanned"></div>
<div class="glyphicon glyphicon-check ng-show" ng-show="requirement.scanned"></div>{{requirement.scanned}}
<div class="col-md-4">
<input type="checkbox" ng-model="requirement.scanned">
</div>
</td>
<td>{{requirement.partId}} - {{requirement.partDescription}}</td>
</tr>
</table>
</form>
</div>
edit 2 -- Html that invokes the directive operation-Requirements and the on page display of the requirements hidden with ng-show.
<div class="row" ng-hide="requirementsFulfilled" >
<operation-Requirements></operation-Requirements>
</div>
<div class="col-md-12" ng-show="requirementsFulfilled">
<table class="table table-hover">
<tr ng-repeat="requirement in requirements">
<td>{{$index + 1 }}</td>
<td>
<div class="glyphicon glyphicon-barcode ng-hide" ng-hide="requirement.scanned"></div>
<div class="glyphicon glyphicon-check ng-show" ng-show="requirement.scanned"></div>
</td>
<td>{{requirement.partId}} - {{requirement.partDescription}}</td>
</tr>
</table>
</div>
So maybe this will help point you in the right direction. What I've done is pulled out the requirements stuff into its own service. Now you have a singleton that handles everything that deals with parts. When its updated in one place its updated everywhere. The directive no longer needs that other controller.
http://plnkr.co/edit/Nej79OI3NrKcrkMNix3D?p=preview
app.service('partsService', function() {
return {
requirementsFulfilled: false,
requirements: [],
getRequirements: function () {
this.requirements.push({partId: 1, partDescription: 'Some Desc', scanned: false});
this.requirements.push({partId: 2, partDescription: 'Some Desc 2', scanned: true});
},
submitScan: function (id) {
this.requirements.filter(function (part) {
return part.partId === id;
}).map(function (part) {
part.scanned = true;
});
this.requirementsFulfilled = this.requirements.filter(function (part) { return !part.scanned }).length === 0;
}
};
});

filling a textarea with ng-repeat or ng-model so that it does not create a new textarea one on top of the other with the iterated data

im having issues trying to fill a single 10 row textarea with data using ng-repeat instead it creates a new textarea for every data entry. how can i just insert into one? and i would like to make the size of the textarea dynamic to the number of entries enterd by ng-repeat
this is my js file
var WaitingRequisitionsController = function($scope, $rootScope, $modal, $window, items) {
$rootScope.title = 'Direct Requisitions';
$scope.items = items;
$scope.formatDate = function (x) {
return moment(x).format("M/D/YYYY");
};
};
and this is my html file, specifically the area im trying to insert.
<div class="row ">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<div class="form-group">
<label>Items</label>
<div ng-repeat="item in req.items">
<textarea ng-model="item.description" class="form-control" type="text" readonly="readonly"></textarea>
</div>
</div>
</div>
</div>
and this does the same thing
<div class="row ">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<div class="form-group">
<label>Items</label>
<textarea ng-repeat="item in req.items" class="form-control" type="text" readonly="readonly">{{item.description}}</textarea>
</div>
</div>
</div>
i have changed my js to look like this
var WaitingRequisitionsController = function($scope, $rootScope, $modal, $window, items) {
$rootScope.title = 'Direct Requisitions';
//$scope.items = items;
$scope.formatDate = function (x) {
return moment(x).format("M/D/YYYY");
};
};
function TodoCtrl($scope) {
$scope.items = items.join('\n');
$scope.$watch('items', function (items) {
$scope.myArray = items.split('\n');
console.log('$scope.myArray', $scope.myArray);
});
}
and my html to look like this
<!-- <div class="row ">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<div class="form-group" ng-app>
<label>Items</label>-->
<div ng-app>
<div ng-controller="TodoCtrl">
<textarea rows={{rows}} class="form-control" ng-model="myStr" type="text" readonly="readonly"></textarea>
</div>
</div>
<!-- </div>
</div>
</div>-->
but nothing populates if i change this around to look like this
http://jsfiddle.net/U3pVM/8165/
it works..i dont get it
i need item.description i dont know if that has anything to do with it
Join the items into a single string, separated by newlines
var WaitingRequisitionsController = function($scope, $rootScope, $modal, $window, items) {
$rootScope.title = 'Direct Requisitions';
$scope.items = items
.map(function (item) {
return item.description;
})
.join('\n');
$scope.rows = items.length;
$scope.formatDate = function (x) {
return moment(x).format("M/D/YYYY");
};
};
You can then use the length of the items array to set the number or rows on the text area.
<textarea type="text" class="form-controler readonly="readonly" rows="rows"
ng-model="items">
</textarea>
Plunker for example: http://plnkr.co/edit/SXSl4nHJi8ptufP6wTd4?p=preview
You're ng-repeating <textarea> (either in itself, or through a containing div) so that it iterates over each instance of item. What you need to do is get rid of the ng-repeat all together and use ng-model to concatenate a string, as demonstrated in ajs's answer.

Kendo UI "checked" MVVM binding not working for last radio button in external template

I have quite interesting and disturbing problem to solve. I am working on project using MVVM Kendo UI pattern and I have issue with data-bind: checked for radio buttons.
When I bind some variable from VM to view using data-bind, it is binded successfully for all radio buttons except the very last one. So whenever I change radio value to the last one - variable in VM is not changed and therefore no attached listeners to this variable are called.
HTML view:
<div data-role="modalview"
class="dialogStyle width60em"
data-hide="kitkat.widgets.zivotniPojisteniDialog.hide"
data-model="kitkat.widgets.zivotniPojisteniDialog"
data-init="kitkat.widgets.zivotniPojisteniDialog.init">
<div class="dialogContainer kitkat-switches">
<form id="form">
<div data-role="scroller" class="scroller">
<div class="row">
<span data-bind="source: nameSource" data-template="name-tmpl"></span>
<script type="text/x-kendo-template" id="name-tmpl">
<input type="radio" name="firstname" value="#= idx#" data-bind="checked: nameSelectedValue"
id="firstname#= idx#" />
<label class="black" for="firstname#= idx#">#= name#</label>
</script>
</div>
<div id="tables">
<!-- example tables, originally created by nested external templates -->
<table id="table0" data-bind="visible: firstnameChanged">
<tr class="row">
<td class="firstColumn"></td>
<td class="secondColumn"></td>
<td class="thirdColumn"></td>
</tr>
</table>
<table id="table1" data-bind="visible: firstnameChanged">
<tr class="row">
<td class="firstColumn"></td>
<td class="secondColumn"></td>
<td class="thirdColumn"></td>
</tr>
</table>
<!-- - - - - - - -->
</div>
</div>
</form>
</div>
</div>
JS viewmodel:
<script>
var _dialog = kendo.observable({
// hardcoded data for this example
nameSource: [
{
"idx" : 0,
"name" : "John"
},
{
"idx" : 1,
"name" : "George"
}
],
nameSelectedValue: null, // problematic variable
init: function(e) {
var self = _dialog;
self._view = e.sender;
self._view.shim.popup.options.animation.open.effects = "slideIn:down";
$(self._view.element).closest('.km-shim').addClass('dialogs-shim');
self.initView("form");
self.bind("closed", function() {self.hide();});
},
show: function(jeProDeti) {
var self = _dialog;
self._view.open();
},
hide: function() {
},
cancel: function() {
kitkat.touch( function() {
var self = _dialog;
self.trigger('done');
self._view.close();
self.trigger('closed');
});
},
firstnameChanged: function(e) {
var self = _dialog;
var idx = e.idx;
var selectedIdx = parseInt(self.get("nameSelectedValue")); // getter for registering "nameSelectedValue" change
if(idx === selectedIdx) { // table is visible if corresponding radio value is selected
return true;
}
return false; // otherwise it is invisible
}
});
</script>
Thank you for any advice
Ok the problem was kind of weird for me. I wrapped every radio input into its own <span> and it worked

Categories