Dynamic HTML partial based on REST response - javascript

I have an application I am building using an Angular JS front end and a REST-based API back end feeding a MySQL database. There are REST calls made from the front end to the back end to populate or retrieve data in the database. I want to add a drop down selection box to my angular JS front end home page. I want the selection to trigger a REST call to the database, to retrieve a specific value and have that value become a part of a dynamically loaded html partial.
As an example, the drop down would select a model of a car (Toyota Corolla, Honda Accord, etc.) When you select that model, the controller would make a REST call to the appropriate table(s) to get the rest of the information for that car (MPG, size, weight, etc.) Once it did this, it would load a partial HTML on the page that was a template HTML file but with dynamic content. So the page loaded would be /#/carInfo?toyotaCorolla. The template partial html file would load and then the tables on the template would populate with the response from that REST call. So I would essentially have a single template for that page, but it would call a new VERSION of the page based on what was selected.
I am thinking about this in my head and I do not have my application code with me. This question is not for the actual code solution, but for someone to either write up some pseudo code or point me to a demo/example online that is similar to this...if it is even possible. I am doing searches on my own, but I may be searching for the wrong terminology to get this accomplished. Any pointers or help on this would be appreciated.
UPDATE:
Now that I am home, here is a snippet of the code I am having issues with.
<ul class="nav navbar-nav">
<li></li>
<li class="dropdown">
<a href="javascript:void(0)" data-target="#" class="dropdown-toggle" data-toggle="dropdown">
Select a car...
<b class="caret"></b></a>
<ul class="dropdown-menu">
<li ng-model="selectedCar.value" ng-repeat="x.car for x in cars"
ng-change="selectedCarChanged()"></li>
</ul>
</li>
</ul>
That is not populating correctly. I have the same ng code for a <select> implementation using ng-options instead of ng-repeat. I was hoping it would be a simple transition, but the CSS version using the lists is not working.

Please find the code snippet below. Hope this will be helpful
car-list.html
<div ng-controller="carListController">
<select ng-model="selectedCar" ng-change="onSelectCar(selectedCar)">
<option ng-repeat="car in cars">{{car}}</option>
</select>
</div>
carListController.js
app.controller('carListController', function($scope, $location) {
$scope.carList = ['Honda', 'Toyota', 'Suzuki', 'Hyundai'];
$scope.onSelectCar = function(car) {
$location.path('#/carInfo').search({carInfo: car});
}
});
carInfo.html
<div class="carDetails">
<span>Car Name: {{car.name}}</span>
<span>Car Model: {{car.model}}</span>
<span>Car Year: {{car.year}}</span>
<span>Car Size: {{car.size}}</span>
</div>
carInfoDetailsController.js
app.controller('carInfoController', function($scope, $location, $http) {
$scope.car = {};
$scope.init= function() {
$http.get('url/' + $location.search('carInfo'), function(response) {
$scope.car = response;
});
};
$scope.init();
});
appConfig.js
app.config(function($routeProvider){
$routeProvider.when('/carInfo'{
templateUrl: "carInfo.html",
controller: "carInfoController"
});
});

something like:
//in a service
(function() {
function MyService($http) {
var myService = {};
MyService.accessMultiTool = function(){
var args = Array.from(arguments);
var method, url, authorization;
args.forEach(function(item){
if('method' in item){
method = item.method;
}else if ('url' in item){
url = item.url;
}else if ('authorization' in item){
authorization = item.authorization;
}
});
delete $http.defaults.headers.common['X-Requested-With'];
return $http({
method: method,
origin: 'http://someclient/',
url: url,
headers: {'Authorization': authorization}
}).error(function(status){generate some error msg});
};
return MyService;
}
angular
.module('myApp')
.factory('MyService', ['$http', MyService]);
})();
//in a controller
(function () {
function MyCtrl(MyService) {
var myController = this;
this.car_model_options = ["Honda", "Chevy", "Ford", "Nissan"];
this.bound_car_model_obj = {
model: null
};
this.getCarModel = function(){
MyService.accessMultiTool({method: 'GET'}, {url: 'http://somebackend/api/cars/' + myController.bound_car_model_obj.model}, {authorization: this.activeMember.auth}).then(function(data){
myController.setCurrCarModel(data);
});
this.setCurrCarModel = function(data){
myController.currently_selected_car_model = data;
};
};
};
angular
.module('myApp')
.controller('MyCtrl', ['MyService', MyCtrl]);
})();
//in a template
<div ng-controller="MyCtrl as mycontroller">
<select data-ng-init="this.bound_car_model_obj.model = mycontroller.car_model_options[0]" data-ng-model="this.bound_car_model_obj.model" data-ng-options="option for option in mycontroller.car_model_options" >
</select>
<table>
<tr ng-repeat="car in mycontroller.currently_selected_car_model>
<td>{{car.someproperty}}>/td>
<td>{{car.someotherproperty}}>/td>
</tr>
</table>
</div>

Related

How to display a returned json in angular view?

I am implementing a search in the github repository.
I need to display the information that i get from here: https://api.github.com/search/repositories?q=bootstrap . for instance into a view or HTML
<div ng-app="newsearchApp">
<div ng-controller="MainCtrl">
<form action="#/about" method="get">
<input ng-model="searchText" />
<button ng-click="search()">Search</button>
</form>
</div>
</div>
the code for searching the Github repository;
angular.module('newsearchApp')
.controller("MainCtrl", ["$scope", function($scope) {
$scope.searchText = "";
$scope.search = function() {
console.log($scope.searchText);
var item = $scope.searchText;
// console.log(item)
var GithubSearcher = require('github-search-api');
var github = new GithubSearcher({username: 'test#something.com', password: 'passwordHere'});
var params = {
'term': $scope.searchText
};
//i am not certain about the 'userData'
github.searchRepos(params, function(data) {
console.log(data);
$scope.userData = data; //i am not certain about the 'repoData'
});
} }]);
the problem is here, when populating the json object to HTML
<div ng-repeat="repo in userData | filter:searchText | orderBy:predicate:reverse" class="list-group-item ">
<div class="row">
<div class="col-md-8">
<h4>
<small>
<span ng-if="repo.fork" class="octicon octicon-repo-forked"></span>
<span ng-if="!repo.fork" class="octicon octicon-repo"></span>
<small>{{repo.forks_count}}</small>
</small>
<a href="{{repo.html_url}}" target="_blank" >
{{repo.name}}
</a>
<small>{{repo.description}}</small>
<small>{{repo.stargazers_count}}</small>
<a href="{{repo.open_issues_count}}" target="_blank" >
Open Issues
</a>
<small>{{}}</small>
</h4>
</div>
</div>
</div>
the results are null on the HTML but are not null on the console.
thanks in advance
the results are null
The problem is, that Angular doesn't notice that the GitHub server has answered and doesn't update the view. You have to tell Angular manually to re-render the view. Try calling $scope.$apply():
github.searchRepos(params, function(data) {
console.log(data);
$scope.userData = data;
$scope.$apply();
});
If you'd make your request to the GitHub API with Angulars $http service, then this would not be needed - you'll only need $scope.$apply() if something asynchronous happens which doesnt live in the "Angular world" - for example things like setTimeout, jQuery ajax calls, and so on. That's why there are Angular wrappers like $timeout and $http.
More details: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
The GitHub API can be accessed using the AngularJS $http service:
app.controller("myVm", function($scope,$http) {
var vm = $scope;
var url = "https://api.github.com/search/repositories?q=bootstrap"
$http.get(url).then(function onSuccess(response) {
vm.data = response.data;
console.log(vm.data);
})
})
HTML
<div ng-app="myApp" ng-controller="myVm">
<div ng-repeat="item in data.items">
{{item.full_name}}
</div>
</div>
The DEMO on JSFiddle
Since you're not using the Angular $http service, angular is not aware of the changes. You need to manually tell Angular to re-render and evaluate by using
$scope.$apply();

Angularjs + directive Isolate two way data binding not working

I try to update the list using directive template. But its not update the data after http request.
test.html:
<div ng-repeat=" comment in [{name:"A"},{name:"B"},{name:"C"}]">
<div lookup-product-icon lookup="lookupProduct(comment)" products="products"></div>
</div>
<div lookup-products></div>
....
Directive:
var app = angular.module('myApp');
app.directive('lookupProductIcon', function() {
return {
scope : {
lookup : "&"
},
template : '<div ng-click="lookup()">Use me!</div>',
};
});
app.directive('lookupProducts', function() {
return {
restrict : 'EA',
transclude : false,
scope : {
products : '='
},
templateUrl : 'lists.html'
};
});
Controller
$scope.products = [];
$scope.lookupProduct = function(lists) {
var details = {
name : lists.name,
host : $scope.host_name
};
productService.lookupProduct(details).then(function(data) {
$scope.products = data.list;
console.log($scope.products);
//Here display the lists in developer tools.
}).catch(function(data) {
if (data.message) {
alert(data.message);
}
});
};
List.html:
<ul>
<li ng-repeat = "product in products"> {{product.name}} </li>
</ul>
Once I click the "Use me!" means then i need to send the http request and then display the lists for the respective content in list.html.
lookupProduct function working but only thing is the products not updating.
Details:
I added two directives.
1. lookupProductIcon - Display the text. Once this text clicked means need to the http get request and then response need to update in list.html (lookupProducts directive)
2. lookupProducts - Here the the data not updating.
Your lookupProducts directive has a scope variable products that is not being passed in your html markup.
You need to pass in an array of products to your lookupProducts directive.
<div lookup-products products="products"></div>

AngularJS Filter expression not being updated

I have am dealing with two HTML files and one controller. In one HTML file I have a search bar:
<a ui-sref="allSubmissions">
<input id="searchBar" ng-controller="submissions" ng-model="searchString" class="searchBar" type="text" placeholder="Search">
</a>
Along with some other stuff. In a separte HTML file, I have a list of submissions that I populate with ng-repeat:
<div class="container" ng-controller="submissions">
<ul class="subsList">
<ul>
<li ng-repeat="item in submissionCollectionTest | filter: searchString" class="submissionDivider hover">
<span class="ageText">{{item.age}}</span>
<span class="submissionsText">{{item.submission}}</span>
<span class="descriptionText">{{item.description}}</span>
</li>
</ul>
</ul>
</div>
Along with some other code. It makes sense in my complete app that these files be separate, however, I cannot get the search input to tie to the filter expression and automatically update.
In my controller, i have the following scope variable:
myApp.controller('submissions',function($scope){
$scope.searchString = '';
When I click in the search bar, it takes me to the new page with shows all the content populated from the ng-repeat, then I want to filter the content by typing in the search bar. This does work when I have the search bar code in the same place as the content. How can I update "searchString" globally so that the filter responds when it changes? Thanks
You could use a broadcast from one controller and listen in another. If you're using multiple routes, then you'll want to store the search term in a service.
Example: https://jsfiddle.net/h0bd88dc/
function SearchSubmissionsCtrl($rootScope,Service) {
var vm = this;
vm.searchString = Service.searchString;
vm.search = search;
function search() {
Service.searchString = vm.searchString;
$rootScope.$broadcast('search', vm.searchString);
}
}
function SubmissionsCtrl($scope,Service) {
var vm = this;
vm.searchString = Service.searchString;
vm.items = [{
age: 22,
submission: 'Yes',
description: 'Yo'
}, {
age: 5,
submission: 'Derp',
description: 'Hey'
}];
$scope.$on('search', function(e, string) {
vm.searchString = string;
})
}
function Service() {
var service = {
searchString: null
};
return service;
}

Angulrjs: A controller doesn't send a value via a factory with the "as" statement

I've been teaching myself how to use the as statement of Angularjs's controller, but struggling to make controllers communicate with others, using the as syntax.
<script type="text/javascript">
angular.module('angularApp', [])
.factory('MessageService', function(){
var message = {
addedItem: "initialMessge"
};
return {
returnMessage: message//This is supposed to be the "var message" defined above
};
})
.controller('DiaplayingProductController', function(MessageService){
var instance = this;
this.data = {
message: MessageService.returnMessage.addedItem
};
})
.controller('ProductController', function($scope, $http, MessageService) {
var instance = this;
this.data = {
message: MessageService.message,
//There are other stuff here
};
this.addItem = function(productName) {
$http({
//other tasks
}).then(function addSucces(response) {
instance.data.message.addedItem = productName;
});
};
});
<span ng-controller="DiaplayingProductController as dpc" ng-bind="dpc.data.message"></span>
<div ng-controller="ProductController as pc">
#foreach ($products as $index => $product)
<div class="product">
<button ng-click="pc.addItem({{$product->name}})>
Add it to Cart
</button>
</div>
#endforeach
</div>
I use Laravel, so {{$product->name}} and #foreach are Laravel's expression.
In a nutshell,
There are one <span> and multiple <button>s, based on the result of #foreach (Again, I use Laravel, so this is basically the same thing as php's foreach)
When one of the <button> is pressed, the content of <span> is supposed to be updated.
The event is triggered in ProductController, which is supposed to update message of DiaplayingProductController, via MessageService.
The message is not going to be sent to the span tag.
This question may be silly. However, there are not many information resources out there which deal with this as statements, so I'd like to ask some advice here. Thank you in advance!
What's this #foreach?
There's a coma in your attributes. Shouldn't be there.
The expression in your ng-click has a missing parenthesis. Also, it should be an expression, therefore the {{}} have nothing to do here.
The data object are not shared between the controllers. You should:
use directives and pass the data using attributes ('=').
set the data in the $scope, which is not as good a solution
use a service as an intermediary (each controller can set/get the value
from that service)

$watch got unexpected multiple events in AngularJS?

I am trying to use AngularJS and moment.js in-order to format time after the json data loaded, and I used $watch to monitor the $scope.comments, but not sure why the $watch recognized 3 events (the result set from json contains 3 items) instead of 1-time as I expected. The console.lof('changed') has been executed 3 tiem
var MyApp = angular.module('MyApp', ['ng', 'commentController']);
MyApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('', {
templateUrl: '/partials/comment-list.html',
controller: 'CommentListCtrl'
});
}
]);
MyApp.directive("timeago", function () {
return function ($scope, element, attrs) {
$scope.$watch("comments", function () {
$('.timeago').each(function (index) {
console.log('chaneged');
$(this).removeClass('timeago');
var time = moment($(this).text());
//console.log(time.fromNow());
$(this).text(time.fromNow());
})
});
};
});
/* Controllers */
var commentController = angular.module('commentController', []);
commentController.controller('CommentListCtrl', function CommentListCtrl($http, $scope) {
$scope.comments = [];
$http.get('/api/json?n=3').success(function (data) {
$scope.commentsLoaded(data);
});
$scope.commentsLoaded = function (data, status) {
$scope.comments = data;
}
});
and the template:
<div ng-Controller="CommentListCtrl">
<ul class="comments" timeago>
<li ng-repeat="comment in comments">
<span class="timeago">{{comment.time}}</span>
<p>{{comment.content}}</p>
</li>
</ul>
</div>
Thank you very much for any help.
In your case, the reason $watch executes 3 times is:
The first time it executes is on startup, where newValue == undefined
The second time is when you call this line: $scope.comments = [];
The third time is when the json is received: $scope.comments = data;
It has nothing to do with your json has 3 items.
however, not sure why the console.log($(this).text()); after the data
loaded only get this : {{comment.time}} It seems that the event was
catched before the template rendered
Because at the time, angular does not update its bindings yet and the view is not updated.
For separations of concern and how we should work with mvc structure like angular, view is for displaying, you should not access data from there, access it though model instead. In your case, you're trying to format the display, it should be the job of a filter
Write a filter like this:
angular.module('commentController').
filter('dateFormat', function() {
return function(input) {
return moment(input).fromNow();
}
});
Use it in HTML, don't need timeago directive:
<div ng-Controller="CommentListCtrl">
<ul class="comments">
<li ng-repeat="comment in comments">
<span class="timeago">{{comment.time | dateFormat }}</span>
<p>{{comment.content}}</p>
</li>
</ul>
</div>
The watch method takes a function with 2 arguments (newValue,oldValue). You can check these values when the watch is executed.
$scope.$watch("comments", function (newValue,oldValue) {
From what i can tell, the first time it executes is on setup, where oldValue is null. Then on any other assignment. Check the values and you would know.
To handle it correctly put checks like
if(newValue && newValue!=oldValue) {
//do something
}

Categories

Resources