Related
I am using amcharts as a custom directive. Now I want to fetch the dataProvider of this AmChart from the output of the $http.get service using webservices.
But I am unable to get this dynamically assigned to the dataprovider of the amChart.
var app=angular.module('mainApp',[]);
app.service('dataProviderService',function($http){
this.getData= function(){
return $http.get('jaxrs/WebService/getJSONData');
};
});
app.directive('myChart',['dataProviderService',function (dataProviderService) {
return {
restrict: 'E',
replace:true,
template: '<div id="chartdiv" style="min-width: 310px; height: 400px; margin: 0 auto"></div>',
link: function (scope, element, attrs) {
scope.data={};
dataProviderService.getData().then(function(response){
scope.data=response.data;
},function(error){
scope.status="Show error";
});
var chart = false;
var initChart = function() {
if (chart) chart.destroy();
var config = scope.config || {};
chart = AmCharts.makeChart( "chartdiv", {
"theme": "none",
"type": "serial",
"dataProvider": dataProviderService.newData(),
"categoryField": "OT",
"depth3D": 20,
"angle": 30,
"categoryAxis": {
"labelRotation": 90,
"gridPosition": "start"
},
"valueAxes": [ {
"title": "availability"
} ],
"graphs": [ {
"valueField": "availability",
"colorField": "color",
"type": "column",
"lineAlpha": 0.1,
"fillAlphas": 1
} ],
"chartCursor": {
"cursorAlpha": 0,
"zoomable": false,
"categoryBalloonEnabled": false
},
"export": {
"enabled": true
}
} );
};
initChart();
}//end watch
}
}]) ;
Assuming your newData() method is an asynchronous $http.get() request like your getData() method, you need to either call makeChart after the request resolves itself or tell the chart to redraw itself by calling validateData() when the request resolves itself. Here's an example of doing this inside the chart's init event:
chart = AmCharts.makeChart( "chartdiv", {
// ... omitted ...
"dataProvider": [],
// ... omitted ...
"listeners": [{
"event": "init",
"method": function(e) {
dataProviderService.newData().then(function(response) {
e.chart.dataProvider = response;
e.chart.validateData();
}, function(error) {
// do something else
});
}
}]
} );
I was running through a set of Angular videos on YouTube and found out that .success is deprecated, and to use .then instead. I get a 404 error using both a .json file and a .txt file. I tried using .txt as people mentioned browsers don't allow local files to access other local files.
This is the $http request I have at the moment
$http.get('data/ninjas.txt').then(function(response) {
// Success!!!
$scope.ninjas = response.data;
});
This is my .json file which is valid through JSONLint
[{
"name": "Yoshi",
"belt": "green",
"rate": 50,
"available": true,
"thumb": "content/img/yoshi.png"
}, {
"name": "Crystal",
"belt": "yellow",
"rate": 30,
"available": true,
"thumb": "content/img/crystal.png"
}, {
"name": "Ryu",
"belt": "orange",
"rate": 10,
"available": true,
"thumb": "content/img/ryu.png"
}, {
"name": "Shaun",
"belt": "black",
"rate": 1000,
"available": true,
"thumb": "content/img/shaun.png"
}]
I tried testing using both httpster and using Brackets built in live preview. I get a 404 error, but the file does for sure exist as you can see in the image
If it helps, this is my whole app.js file
var myNinjaApp = angular.module('myNinjaApp', ['ngRoute']);
myNinjaApp.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/home', {
templateUrl: 'views/home.html'
})
.when('/directory', {
templateUrl: 'views/directory.html',
controller: 'NinjaController'
})
.otherwise({
redirectTo: '/home'
});
}]);
myNinjaApp.controller('NinjaController', ['$scope', '$http', function($scope, $http){
$scope.removeNinja = function(ninja){
var removedNinja = $scope.ninjas.indexOf(ninja);
$scope.ninjas.splice(removedNinja, 1)
};
$scope.addNinja = function(){
$scope.ninjas.push({
name: $scope.newninja.name,
belt: $scope.newninja.belt,
rate: parseInt($scope.newninja.rate),
available: true
});
$scope.newninja.name = "";
$scope.newninja.belt = "";
$scope.newninja.rate = "";
};
$http.get('data/ninjas.txt').then(function(response) {
// Success!!!
$scope.ninjas = response.data;
});
}]);
To make the answer complete,
Your root of your application is 'index.html', and because Angular is running within 'index.html', all files you load in your files are relative to your 'index.html'.
An example of that is seen in your route configuration, where your templates are loaded starting at 'views/*', which is a child folder of your 'index.html'
myNinjaApp.controller('NinjaController', ['$scope', '$http', function ($scope, $http) {
$http({
url: "data/ninjas.json",
method: "GET"
}).then(function (resp) {
$scope.ninjas = resp;
}, function (resp) {
// bla bla bal
});
$scope.removeNinja = function (ninja) {
var removeNinja = $scope.ninjas.indexOf(ninja);
$scope.ninjas.splice(removeNinja, 1);
}
$scope.addNinja = function () {
$scope.ninjas.push({
name: $scope.newninja.name,
belt: $scope.newninja.belt,
rate: parseInt($scope.newninja.rate),
available: true
});
$scope.newninja.name = "";
$scope.newninja.belt = "";
$scope.newninja.rate = "";
};
$scope.removeAll = function () {
$scope.ninjas = [];
};
$scope.sort = function (keyname) {
$scope.sortKey = keyname;
$scope.reverse = !$scope.reverse;
}
}]);
As for all who struggle getting not an array with net ninjas and the code above you now get the whole HTTP response under data not the JSON file itself you need to get the data property of the request so like this:
$http.get('app/Data/ninja.json').then(function(data) {
$scope.ninjas = data.data;
}, function() {
});
I have what I think is the correct accessor syntax for binding my UI-Grid control, I don't get any errors or any data. I just get a warning about Mutating the prototype.
My json data structure is like this:
{
"records": [
{
"acctIdInfo": {
"acctId": "257905480",
"acctCode": "ABC10101102",
"acctName": "BIG CORPORATION",
"acctRole": [
"C"
]
},
"acctNameAddr": {
"addressLine": [
"7280 JAMISON ST"
],
"cityName": "VANCOUVER",
"stateCd": "US-WA",
"countryCd": "US",
"postalCd": "97979"
}
}
]
}
The code in my AngularJS controller to bind is:
var app = angular.module('app', ['ui.grid', 'ngResource'])
.factory('jsonDataFactory', function ($resource) {
return {
custData: $resource('data.json', {}, {
query: {method: 'GET', params: {}, isArray: false}
}),
};
});
app.controller('MainCtrl', ['$scope','$resource','jsonDataFactory', function ($scope,$resource, jsonDataFactory) {
$scope.gridOptions = {
enableRowSelection: true,
enableSelectAll: true,
selectionRowHeaderWidth: 35
};
$scope.gridOptions.columnDefs = [
{ name: 'acctIdInfo.acctId' },
{ name: 'acctIdInfo.acctCode'},
{ name: 'acctIdInfo.acctName'},
{ name: 'acctNameAddr.addressLine' }
];
$scope.gridOptions.data = jsonDataFactory.custData.query().records;
$scope.CustomerData = [];
$scope.CustomerData = jsonDataFactory.custData.query();
console.log($scope.CustomerData);
$scope.gridOptions.data = $scope.CustomerData.records;
}]);
Here is my plnk of what I tried -
I think I'm close...
Do assign a data to ui-grid data source once ajax call response comes back. I assumed that you had used $resource, so you can have promise over it to attach callback function.
jsonDataFactory.custData.query().$promise.then(function(response){
$scope.CustomerData = response;
console.log($scope.CustomerData);
$scope.gridOptions.data = $scope.CustomerData.records;
});
I have the following angular app to create a menu of sections/products.
at present when rendered and hitting the 'add' button that is rendered within each li I want to add a section/product as a sub of that section however multiple new children are created.
ultimately I wish to display a form which when submitted will create the child but that is the next step. Right now I need to limit the scope to the current section and not have multiple bound clicks.
If you need more information please state and I will post in an edit.
Some sample data data.
{
"sections":[
{
"name":"Flags",
"sections":[
{
"name":"Europe",
"sections":[],
"products":[
{ "name": "France" },
{ "name": "Germany" },
{ "name": "Ireland" },
{ "name": "England" }
]
},
{
"name": "Africa",
"sections":[],
"products":[
{ "name": "Egypt" },
{ "name": "Nigeria" },
{ "name": "Chad" }
]
},
{
"name": "South America",
"sections":[],
"products": [
{ "name": "Brasil" },
{ "name": "Argentina" },
{ "name": "Peru" }
]
}
],
"products":[]
},
{
"name": "Maps",
"sections":[
{
"name": "Africa",
"sections":[],
"products":[
{ "name": "Egypt" },
{ "name": "Nigeria" },
{ "name": "Chad" }
]
},
{
"name": "South America",
"sections":[],
"products": [
{ "name": "Brasil" },
{ "name": "Argentina" },
{ "name": "Peru" }
]
}
],
"products":[]
}
],
"products":[]
}
The app.
'use strict';
var menuApp = angular.module('menuApp', []);
menuApp
.directive('sections', function () {
return {
restrict: "E",
replace: true,
scope: {
sections: '='
},
template: '<ul><section ng-repeat="section in sections" section="section" /></ul>'
};
})
.directive('section', function ($compile) {
return {
restrict: "E",
replace: true,
scope: {
section: '=section'
},
template: '<li class="section">{{section.name}} <button ng-click="addSub(section)">Add</button></li>',
link: function (scope, element, attrs, controller) {
if (angular.isArray(scope.section.sections)) {
element.append("<sections sections='section.sections'></sections>");
$compile(element.contents())(scope);
}
if(angular.isArray(scope.section.products)){
element.append("<products products='section.products'></products>");
$compile(element.contents())(scope);
};
},
controller : function($scope){
console.log($scope);
$scope.addSub = function (section){
//console.log(section,'Adding Sub');
section.sections.push({"name":"Section","sections":[],"products":[]});
};
}
};
})
.directive('products', function () {
return {
restrict: "E",
replace: true,
scope: {
products: '='
},
template: '<ul><product ng-repeat="product in products" product="product"></product></ul>'
};
})
.directive('product', function ($compile) {
return {
restrict: "E",
replace: true,
scope: {
product: '='
},
template: '<li class="product">{{product.name}}</li>'
};
});
menuApp.controller('menuCtrl', function menuCtrl($scope,$http) {
$http.get('/ajax/getvenuesmenu?venueID='+venueMenu.venueId).success(function(resp) {
$scope.sections = resp;
});
$scope.add = function(data){
data.push({"name":"Section","sections":[]});
};
});
Took me a bit to figure it out but here's the basic problem, you are compiling the full contents of section 2 extra times and each compile seems to add a new event handler.
Instead of compiling the contents of element each time you make an append of new template, compile the template itself (outside of the DOM) and then append the compiled template. This way the ng-click handler doesn't get compiled again other than initial scope creation
Here's an abbreviated version with one template appended:
link: function (scope, element, attrs, controller) {
if (angular.isArray(scope.section.sections)) {
/* compile outside of the DOM*/
var subsections = $compile("<sections sections='section.sections'></sections>")(scope);
/* append compilation*/
element.append(subsections);
}
DEMO
Another approach would be to create a complete template string in link by checking for subsections and products, then compiling everything all at once....instead of using template option
Code for alternate approach compiling complete section at once:
.directive('section', function ($compile, $timeout) {
return {
restrict: "E",
scope: {
section: '=section'
},
link: function (scope, element, attrs, controller) {
var template = '<li class="section">{{section.name}} <button ng-click="addSub(section)">Add</button>';
if (angular.isArray(scope.section.sections)) {
template += "<sections sections='section.sections'></sections>";
}
if (angular.isArray(scope.section.products)) {
template += "<products products='section.products'></products>";
};
template += '</li>';
var compiledTemplate = $compile(template)(scope);
element.replaceWith(compiledTemplate);
scope.addSub = function (section) {
section.sections.push({ "name": "Section", "sections": [], "products": []
});
};
}
};
})
DEMO-Alt
I have the following app.js file.
When i run the command with out the "require" it works but does not include the views. When i add the required line i'm getting "store is undefine".
I guess this is because the store are not defined at that point. So what is best play here?
sencha create jsb -a http://mysite.local/ext/cutter/app/index.html -p app.jsb3
app.js
Ext.Loader.setConfig({ enabled: true });
Ext.Loader.setPath('App', '/ext/Cutter/app');
Ext.Loader.require(['App.view.ViewCutter']);
Ext.application({
name: 'Mis',
appFolder: '/ext/Cutter/app',
models: [ 'Cutter', 'Project', 'CutterHistory','Job', 'Part' , 'ClientFinder'],
stores: [ 'Cutters','CutterHistories','Projects', 'Jobs', 'Parts'],
controllers: ['Cutter'],
launch: function () {
Ext.QuickTips.init();
var cmp1 = Ext.create('App.view.ViewCutter', {
renderTo: "mis-application"
});
cmp1.show();
}
});
UPDATE
Here is the jsb created
{
"projectName": "Project Name",
"licenseText": "Copyright(c) 2012 Company Name",
"builds": [
{
"name": "All Classes",
"target": "all-classes.js",
"options": {
"debug": true
},
"files": [
{
"clsName": "Mis.model.Cutter",
"name": "Cutter.js",
"path": "/ext/Cutter/app/model/"
},
{
"clsName": "Mis.store.Cutters",
"name": "Cutters.js",
"path": "/ext/Cutter/app/store/"
},
{
"clsName": "Mis.model.CutterHistory",
"name": "CutterHistory.js",
"path": "/ext/Cutter/app/model/"
},
{
"clsName": "Mis.store.CutterHistories",
"name": "CutterHistories.js",
"path": "/ext/Cutter/app/store/"
},
{
"clsName": "Mis.model.Project",
"name": "Project.js",
"path": "/ext/Cutter/app/model/"
},
{
"clsName": "Mis.store.Projects",
"name": "Projects.js",
"path": "/ext/Cutter/app/store/"
},
{
"clsName": "Mis.model.Job",
"name": "Job.js",
"path": "/ext/Cutter/app/model/"
},
{
"clsName": "Mis.store.Jobs",
"name": "Jobs.js",
"path": "/ext/Cutter/app/store/"
},
{
"clsName": "Mis.model.Part",
"name": "Part.js",
"path": "/ext/Cutter/app/model/"
},
{
"clsName": "Mis.store.Parts",
"name": "Parts.js",
"path": "/ext/Cutter/app/store/"
}
]
},
{
"name": "Application - Production",
"target": "app-all.js",
"compress": true,
"files": [
{
"path": "",
"name": "all-classes.js"
},
{
"path": "",
"name": "app.js"
}
]
}
],
"resources": []
}
controller
Ext.define('Mis.controller.Cutter', {
extend:'Ext.app.Controller',
refs:[
{
ref:'Cutter',
selector:'Cutter'
},
{
ref:'CutterEdit',
selector:'CutterEdit'
}
],
// views: ['ViewCutter'],
stores:[ 'Cutters', 'CutterHistories', 'Clients' , 'Projects' , 'Jobs' , 'Parts' ],
init:function () {
this.control({
'#category menu':{
click:this.onCutterTypeSelect
},
'#cutterGrid button[action=create]':{
click:this.onCutterCreate
},
'#sortby menu':{
click:this.onSortBySelect
},
'#cutterGrid button[action=search]':{
click:this.onSearch
},
'#cutterGrid':{
cellclick :this.onCutterSelectRow
},
'#cutterHistories actioncolumn':{
click:this.onCutterHistoryRemove
},
'#cutterForm button[action=save]':{
click:this.onCutterUpdate
},
'#cutterForm button[action=remove]':{
click:this.onCutterRemove
},
'#cutterForm button[action=create]':{
click:this.onCutterNumberCreate
},
'#cutterForm #ClientDropdown': {
select: this.onClientSelect
},
'#cutterForm #ProjectDropdown': {
select: this.onProjectSelect
},
'#cutterForm #JobDropdown': {
select: this.onJobSelect
}/*,,
'#cutterForm #Clients': {
change: this.onClientSelect
},
'#cutterForm #Projects': {
change: this.onProjectSelect
},
'#cutterForm #Jobs': {
change: this.onJobSelect
}*/
});
},
onLaunch:function () {
var cutterStore = this.getCuttersStore();
cutterStore.load();
var clients = this.getClientsStore();
clients.load();
Ext.getCmp('cutterFieldset').setVisible(false);
},
onLoad:function (selection) {
},
onSortBySelect:function (selModel, selection) {
var action = selection.action;
if (selection != null) {
if (action != "") {
contactUrl = "/Contact/" + action;
sortBy = action;
}
}
},
onClientSelect: function (selModel, selection) {
var projects = this.getProjectsStore();
projects.load({
url: '/Projects/ReadByClientId/' + selection[0].data.Id,
scope: this
});
Ext.getCmp('ProjectDropdown').setValue("---- Select -----");
Ext.getCmp('JobDropdown').setVisible(false);
Ext.getCmp('PartDropdown').setVisible(false);
},
onProjectSelect: function (selModel, selection) {
Ext.getCmp('JobDropdown').setValue("---- Select -----");
var jobs = this.getJobsStore();
jobs.load({
url: '/Jobs/ReadByProject/' + selection[0].data.Id,
scope: this
});
Ext.getCmp('JobDropdown').setVisible(true);
Ext.getCmp('PartDropdown').setVisible(false);
},
onJobSelect: function (selModel, selection) {
var parts = this.getPartsStore();
parts.load({
url: '/Part/Read/' + selection[0].data.Id,
scope: this
});
Ext.getCmp('PartDropdown').setValue("---- Select -----");
Ext.getCmp('PartDropdown').setVisible(true);
},
onClientFinder: function (selModel, selection) {
var clientId = Ext.getCmp('ClientId').value;
var projectId = Ext.getCmp('ProjectId').value;
var jobId = Ext.getCmp('JobId').value;
var partId = Ext.getCmp('PartId').value;
var clientGuid = Ext.getCmp('Clients').value;
var projectGuid = Ext.getCmp('Projects').value;
var jobGuid = Ext.getCmp('Jobs').value;
var partGuid = Ext.getCmp('Parts').value;
var form = Ext.getCmp('cutterForm');
Ext.Ajax.request({
method:'POST',
url:'/Cutter/ClientFinder',
params:{ ClientId:clientId, ClientGuid:clientGuid, ProjectId:projectId, ProjectGuid:projectGuid, JobId:jobId, JobGuid: jobGuid },
success:function (request) {
var data = Ext.decode(request.responseText);
if (data.ClientId != 0) Ext.getCmp('ClientId').setValue(data.ClientId);
if (data.ProjectId != 0) Ext.getCmp('ProjectId').setValue(data.ProjectId);
if (data.JobId != 0) Ext.getCmp('JobId').setValue(data.JobId);
if (data.PartId != 0) Ext.getCmp('PartId').setValue(data.PartId);
Ext.getCmp('Clients').setValue(data.ClientGuid);
Ext.getCmp('Projects').setValue(data.ProjectGuid);
Ext.getCmp('Jobs').setValue(data.JobGuid);
Ext.getCmp('Parts').setValue(data.PartGuid);
}
});
},
onCutterHistoryRemove: function(gridview, el, rowIndex, colIndex, e, rec, rowEl) {
var store = this.getCutterHistoriesStore();
Ext.Msg.confirm('Remove History', 'Are you sure?', function(btn, text){
if (btn == 'yes'){
rec.destroy({
success:function () {
store.remove(rec);
Ext.MessageBox.alert('Status', 'History removed.');
},
callback:function () {
},
failure:function () {
Ext.MessageBox.alert('Status', 'History cannot be removed as it has related items');
}
});
}
});
},
onCutterRemove:function (selection) {
var form = Ext.getCmp('cutterForm');
var record = form.getRecord();
var values = form.getValues();
record.set(values);
var cutterStore = this.getCuttersStore();
Ext.Msg.confirm('Remove Cutter', 'Are you sure?', function(btn, text){
if (btn == 'yes'){
record.destroy({
success:function () {
cutterStore.remove(record);
var view = Ext.widget('EditCutter');
view.close();
},
callback:function () {
},
failure:function () {
Ext.MessageBox.alert('Status', 'This cutter cannot be removed as it has related items');
}
});
}
});
},
onCutterSelectRow : function (item, td, cellIndex, rec, tr, rowIndex, e, eOpts ) {
if (rec != null) {
var view = Ext.widget('EditCutter');
var cutters = this.getCutterHistoriesStore();
cutterNumber = rec.data.CutterNumber;
cutters.load({
url: '/CutterHistory/Read/' + rec.data.Id,
scope: this
});
var form = Ext.getCmp('cutterForm');
form.loadRecord(rec);
/* Load client */
var clientStore = this.getClientsStore();
var clientCombo = Ext.getCmp("ClientDropdown");
var clientUrl = '/Client/Read/';
selectCombo(clientStore, clientCombo, rec.data.ClientGuid, clientUrl);
/* Load projects */
var projectsStore = this.getProjectsStore();
var projectCombo = Ext.getCmp("ProjectDropdown");
var projectUrl = '/Projects/ReadByClientId/' + rec.data.ClientGuid;
selectCombo(projectsStore, projectCombo, rec.data.ProjectGuid, projectUrl);
/* Load job */
var jobsStore = this.getJobsStore();
var jobCombo = Ext.getCmp("JobDropdown");
var jobUrl = '/Jobs/ReadByProject/' + rec.data.ProjectGuid;
selectCombo(jobsStore, jobCombo, rec.data.JobGuid, jobUrl);
/* Load part */
var partsStore = this.getPartsStore();
var partCombo = Ext.getCmp("PartDropdown");
var partUrl = '/Part/Read/' + rec.data.JobGuid;
selectCombo(partsStore, partCombo, rec.data.PartGuid, partUrl);
Ext.getCmp('cutterFieldset').setVisible(true);
Ext.getCmp('CutterSave').setVisible(true);
view.show()
}
},
onCutterCreate:function (selModel, selection) {
var r = Ext.ModelManager.create({
}, 'Mis.model.Cutter');
var view = Ext.widget('EditCutter');
var form = Ext.getCmp('cutterForm');
form.loadRecord(r);
Ext.getCmp('cutterFieldset').setVisible(true);
Ext.getCmp('CutterSave').setVisible(true);
view.show();
},
onCutterNumberCreate:function (selModel, selection) {
var form = Ext.getCmp('cutterForm');
var r = Ext.ModelManager.create({
CutterNumber: cutterNumber
}, 'Mis.model.Cutter');
form.loadRecord(r);
},
onSearch:function (selModel, selection) {
destroyed = Ext.getCmp('Destroyed').value;
var searchBox = Ext.getCmp('SearchTerm');
search = searchBox.getValue();
var cuttersStore = this.getCuttersStore();
cuttersStore.proxy.setExtraParam('sort', sortBy);
cuttersStore.proxy.setExtraParam('search', search);
cuttersStore.proxy.setExtraParam('destroyed', destroyed);
cuttersStore.load({params:{start:0, page:1}});
var url = Ext.String.format('/Cutter/Export/?sortBy={0}&search={1}&destroyed={2}', sortBy, search, destroyed);
Ext.getCmp('ExportCutter').el.down('a').dom.setAttribute('href', url);
},
onCutterUpdate:function (selection) {
var form = Ext.getCmp('cutterForm');
var record = form.getRecord();
var values = form.getValues();
record.set(values);
// var cutterNumbersStore = this.getCutterNumbersStore();
var cuttersStore = this.getCuttersStore();
if (form.getForm().isValid()) {
record.save({
success:function () {
Ext.MessageBox.alert('Status', 'Changes saved successfully.');
// cutterNumbersStore.insert(0, record);
// cuttersStore.load();
},
callback:function () {
},
failure:function () {
Ext.MessageBox.alert('Status', 'Changes could not be saved');
}
});
} else {
Ext.MessageBox.alert('Status', 'Please enter all fields');
}
}
});
function selectCombo(store, combo, selectedValue, url) {
store.load({
url: url,
callback: function(){
combo.setValue(selectedValue);
},
scope: this
});
}
Remove
Ext.Loader.require(['App.view.ViewCutter']);
Your controller App.view.ViewCutter should have line views: ['ViewCutter'] and this effectively would tell Sencha SDK to include App.view.ViewCutter.js file into bundle.