I am trying to plot a graph with Hightchart, my data comes from an REST web service.
I am using angularjs (1.5) to get the data.
my Service look like :
app.factory('ServicesImpl', function($http){
var obj = {};
obj.getData = function(){
return $http.get('http://localhost:8080/chartDepense/');
};
return obj;
});
my controller is :
app.controller('myController', function ($scope, $rootScope, ServicesImpl) {
$scope.chart = ServicesImpl.getData().then(function(r){
return r.data;
});
console.log($scope.chart);
$scope.chartOptions = {
title: {
text: $scope.chart.libelle
},
xAxis: {
categories: $scope.chart.categories ,
title: {
text: 'les X'
}
},
yAxis: {
title: {
text: 'les Y'
}
},
series: [{
data: $scope.chart.peroides
}]
};
});
and I got this :
I don't know can I can get my data in my controller to put in chartConfig?
I'm trying to attach an angular directive to `
{
field:"stateID",
hidden: true,
title: "State",
editor: function (container, options) {
var _statesDirective = $('<div><my-states></my-states></div>');
_statesDirective.appendTo(container);
}`
My diretive looks like this:
appRoot.directive('myStates', function () {
return {
restrict: 'EA',
templateUrl: 'directivesHTML/ddStates.html',
scope:false,
controller: function ($scope)
{
var dsStates = new kendo.data.DataSource({
autoBind: false,
page: 1,
transport: {
read: {
url: "api/util/getStates",
dataType: "json"
}
},
schema: {
model: {
id: "stateID",
fields: {
stateID: { type: 'string' },
name: { type: "string" }
}
}
}
});
dsStates.read().then(function () {
$('#ddStates')
.kendoDropDownList({
dataTextField: "name",
dataValueField: "stateID",
dataSource: dsStates,
optionLabel: '--',
change: function (e) {
}
});
});
}
};
});
For some weird reason, it wont work, if I put the directive someplace else, any outside html page, it works just fine, but not from here. I thought it could be the version, upgraded it to the latest one for this month to no avail.
Any clues ?
-thanks,
You need to compile your html before appending it (using $compile service).
So in your editor: function,
// Specify what it is we'll be compiling.
var to_compile = '<div><my-states></my-states></div>';
// Compile the tag, retrieving the compiled output.
var _statesDirective = $compile(to_compile)($scope);
// Ensure the scope and been signalled to digest our data.
$scope.$digest();
// Append the compiled output to the page.
$compiled.appendTo(_statesDirective);
For more reference, Angular Docs for $compile
Also, how can we use $compile outside a directive in Angularjs
I am very new to AngularJs and hope I can get some help here. Below I have two controllers that are very similar. One is for editing an item and one for adding a new item. I would like to know how I can refactor this code in order to reuse most of this code for both controllers or simply use one controller for both. I originally tried to use one controller for both but the new item page wouldn't let me type anything into the fields. I supposed because there was no current model data like there is when editing.
Any help would be appreciated.
tplApp.controller('editController', function ($scope, $http, $routeParams){
$scope.template = {};
$scope.id = $routeParams.template_id;
$http.get(baseUrl+'templates/get_template/'+$scope.id).success(function(data) {
$scope.template = data;
});
$scope.bodyOptions = {
plugins: 'link image code',
toolbar: 'bold, italic, underline, alignleft, aligncenter, alignright, alignjustify, styleselect, bullist, numlist, outdent, indent, removeformat, mybutton, code',
height: 300,
menubar: false,
statusbar: false,
setup: function(editor) {
editor.addButton('mybutton', {
type: 'menubutton',
text: 'Variables',
icon: false,
menu: [
{text: 'Candidate Name', onclick: function() {editor.insertContent('%name%');}},
{text: 'Company Name', onclick: function() {editor.insertContent('%company-name%');}},
{text: 'Today\'s Date', onclick: function() {editor.insertContent('%date%');}},
{text: 'Your Name', onclick: function() {editor.insertContent('%your-name%');}},
]
});
}
};
$scope.saveTemplate = function() {
$http({
method : 'POST',
url : baseUrl+'templates/save',
data : $.param($scope.template),
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.success(function(data) {
$scope.message = data.message;
if (data.success) {
console.log(data);
$scope.templates = data.templates;
}
});
};
});
tplApp.controller('addController', function ($scope, $http){
$scope.template = {};
$scope.bodyOptions = {
plugins: 'link image code',
toolbar: 'bold, italic, underline, alignleft, aligncenter, alignright, alignjustify, styleselect, bullist, numlist, outdent, indent, removeformat, mybutton, code',
height: 300,
menubar: false,
statusbar: false,
setup: function(editor) {
editor.addButton('mybutton', {
type: 'menubutton',
text: 'Variables',
icon: false,
menu: [
{text: 'Candidate Name', onclick: function() {editor.insertContent('%name%');}},
{text: 'Company Name', onclick: function() {editor.insertContent('%company-name%');}},
{text: 'Today\'s Date', onclick: function() {editor.insertContent('%date%');}},
{text: 'Your Name', onclick: function() {editor.insertContent('%your-name%');}},
]
});
}
};
$scope.saveTemplate = function() {
$http({
method : 'POST',
url : baseUrl+'templates/save',
data : $.param($scope.template),
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.success(function(data) {
$scope.message = data.message;
if (data.success) {
console.log(data);
$scope.templates = data.templates;
}
});
};
});
What you want is a service: https://docs.angularjs.org/guide/services
"You can use services to organize and share code across your app"
Google it and/or look here in SO for more info.
Try these changes. You will need 2 services + 2 controllers (for saveTemplateService.js and buildBodyOptionsService.js ). The services will be injected to the controllers.
At the end,don't forget to add the src of each service in the template/html file.
I think it could be even more reduced (without the $http's success in the controllers) but since we are working with callbacks here, I'm not sure. Try it out ;).
It might not be fully functional because I don't have all your code. But debugging should solve it.
saveTemplateService.js:
app.factory('saveTemplateService', function ( baseUrl, $http ) {
return $http({
method : 'POST',
url : baseUrl+'templates/save',
data : $.param($scope.template), //fix these (injecting them like baseUrl)
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
});
});
buildBodyOptionsService.js:
app.factory('buildBodyOptionsService', function() {
return {
build: function ( editor ) { //maybe editor needs to be injected
var output = {
plugins: 'link image code',
toolbar: 'bold, italic, underline, alignleft, aligncenter, alignright, alignjustify, styleselect, bullist, numlist, outdent, indent, removeformat, mybutton, code',
height: 300,
menubar: false,
statusbar: false,
setup: function(editor) {
editor.addButton('mybutton', {
type: 'menubutton',
text: 'Variables',
icon: false,
menu: [
{text: 'Candidate Name', onclick: function() {editor.insertContent('%name%');}}, // I dont like this functions here. There must be a better way to do this (ex: in a partial html with ng-click)
{text: 'Company Name', onclick: function() {editor.insertContent('%company-name%');}},
{text: 'Today\'s Date', onclick: function() {editor.insertContent('%date%');}},
{text: 'Your Name', onclick: function() {editor.insertContent('%your-name%');}},
]
});
}
};
return output;
}
};
});
editController.js
tplApp.controller('editController', function ($scope, saveTemplateService, buildBodyOptionsService) {
$scope.template = {};
$scope.id = $routeParams.template_id;
$http.get(baseUrl+'templates/get_template/'+$scope.id)
.success(function(data) {
$scope.template = data;
});
// call 1st service
$scope.bodyOptions = buildBodyOptionsService.build( editor );
// call 2nd service
$scope.saveTemplate = saveTemplateService.success( function(data) {
$scope.message = data.message;
if (data.success) {
console.log(data); //use $log.info() instead
$scope.templates = data.templates;
}
});
});
addController.js
tplApp.controller('addController', function ($scope, saveTemplateService, buildBodyOptionsService) {
$scope.template = {};
// call 1st service
$scope.bodyOptions = buildBodyOptionsService.build( editor );
// call 2nd service
$scope.saveTemplate = saveTemplateService.success( function(data) {
$scope.message = data.message;
if (data.success) {
console.log(data); //use $log.info() instead
$scope.templates = data.templates;
}
});
});
Check these links for more info:
custom services in Angular (really well explained): https://youtu.be/rlx1cf7qM0E?list=PL6n9fhu94yhWKHkcL7RJmmXyxkuFB3KSl
promises in services: AngularJS: Performing $http request inside custom service and returning data
(relevant) Angular $http difference between .success() and .then()
I would probably put everything in a single service (templateService). I'm not sure if the bodyOption belongs there but for now I would just put it there. Then I would move the load/save template function to the service.
You could probably do more, for instance, your might set the $scope.templateService = templateService and in your html use templateService.bodyOptions/templates directly.
Also, you could probably move the save.success from the controller to the service aswell.
tplApp.service('templateService', function($http, $routeParams) {
var self = this;
this.template = {};
this.loadTemplate = function() {
$http.get(baseUrl+'templates/get_template/' + $routeParams.template_id)
.success(function(data) {
self.template = data;
});
};
this.saveTemplate = function() {
return $http({
method: 'POST',
url: baseUrl + 'templates/save',
data: $.param(self.template),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
this.bodyOptions = {
plugins: 'link image code',
toolbar: 'bold, italic, underline, alignleft, aligncenter, alignright, alignjustify, styleselect, bullist, numlist, outdent, indent, removeformat, mybutton, code',
height: 300,
menubar: false,
statusbar: false,
setup: function(editor) {
editor.addButton('mybutton', {
type: 'menubutton',
text: 'Variables',
icon: false,
menu: [
{text: 'Candidate Name', onclick: function() {editor.insertContent('%name%');}},
{text: 'Company Name', onclick: function() {editor.insertContent('%company-name%');}},
{text: 'Today\'s Date', onclick: function() {editor.insertContent('%date%');}},
{text: 'Your Name', onclick: function() {editor.insertContent('%your-name%');}},
]
});
}
};
});
tplApp.controller('editAndAddController', function ($scope, templateService){
$scope.template = templateService.template;
$scope.bodyOptions = templateService.bodyOptions;
if(edit) {
templateService.loadTemplate();
}
$scope.saveTemplate = function() {
templateService.saveTemplate()
.success(function(data) {
$scope.message = data.message;
if (data.success) {
console.log(data);
$scope.templates = data.templates;
}
});
};
});
Ideally your controller would probably look like this:
tplApp.controller('editAndAddController', function ($scope, templateService){
$scope.templateService = templateService;
if(edit) {
templateService.loadTemplate();
}
});
Heads up! This is just example, code is not tested!
I have a ui-select field
{
key: 'data_id',
type: 'ui-select',
templateOptions: {
required: true,
label: 'Select label',
options: [],
valueProp: 'id',
labelProp: 'name'
},
controller: function($scope, DataService) {
DataService.getSelectData().then(function(response) {
$scope.to.options = response.data;
});
}
}
How can I access that inner controller in my unit tests and check that data loading for the select field actually works ?
UPDATE:
An example of a test could be as such:
var initializePageController = function() {
return $controller('PageCtrl', {
'$state': $state,
'$stateParams': $stateParams
});
};
var initializeSelectController = function(selectElement) {
return $controller(selectElement.controller, {
'$scope': $scope
});
};
Then test case looks like:
it('should be able to get list of data....', function() {
$scope.to = {};
var vm = initializePageController();
$httpBackend.expectGET(/\/api\/v1\/data...../).respond([
{id: 1, name: 'Data 1'},
{id: 2, name: 'Data 2'}
]);
initializeSelectController(vm.fields[1]);
$httpBackend.flush();
expect($scope.to.options.length).to.equal(2);
});
You could do it a few ways. One option would be to test the controller that contains this configuration. So, if you have the field configuration set to $scope.fields like so:
$scope.fields = [ { /* your field config you have above */ } ];
Then in your test you could do something like:
$controller($scope.fields[0].controller, { mockScope, mockDataService });
Then do your assertions.
I recently wrote some test for a type that uses ui-select. I actually create a formly-form and then run the tests there. I use the following helpers
function compileFormlyForm(){
var html = '<formly-form model="model" fields="fields"></formly-form>';
var element = compile(html)(scope, function (clonedElement) {
sandboxEl.html(clonedElement);
});
scope.$digest();
timeout.flush();
return element;
}
function getSelectController(fieldElement){
return fieldElement.find('.ui-select-container').controller('uiSelect');
}
function getSelectMultipleController(fieldElement){
return fieldElement.find('.ui-select-container').scope().$selectMultiple;
}
function triggerEntry(selectController, inputStr) {
selectController.search = inputStr;
scope.$digest();
try {
timeout.flush();
} catch(exception){
// there is no way to flush and not throw errors if there is nothing to flush.
}
}
// accepts either an element or a select controller
function triggerShowOptions(select){
var selectController = select;
if(angular.isElement(select)){
selectController = getSelectController(select);
}
selectController.activate();
scope.$digest();
}
An example of one of the tests
it('should call typeaheadMethod when the input value changes', function(){
scope.fields = [
{
key: 'selectOneThing',
type: 'singleSelect'
},
{
key: 'selectManyThings',
type: 'multipleSelect'
}
];
scope.model = {};
var formlyForm = compileFormlyForm();
var selects = formlyForm.find('.formly-field');
var singleSelectCtrl = getSelectController(selects.eq(0));
triggerEntry(singleSelectCtrl, 'woo');
expect(selectResourceManagerMock.searchAll.calls.count()).toEqual(1);
var multiSelectCtrl = getSelectController(selects.eq(1));
triggerEntry(multiSelectCtrl, 'woo');
expect(selectResourceManagerMock.searchAll.calls.count()).toEqual(2);
});
Until now, I have been querying the data stores using Rally App SDK, however, this time I have to update a story using the js sdk. I tried looking up for examples for some sample code that demonstrates how the App SDK can be used to update/add values in Rally. I have been doing CRUD operations using Ruby Rally API but never really did it with the app sdk.
Can anyone provide some sample code or any link to where I could check it out?
Thanks
See this help document on updating and creating reocrds. Below are examples - one updates a story, the other creates a story. There is not much going on in terms of UI: please enable DevTools console to see console.log output.
Here is an example of updating a Defect Collection on a User Story:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
console.log("launch");
Rally.data.ModelFactory.getModel({
type: 'User Story',
success: this._onModelRetrieved,
scope: this
});
},
_onModelRetrieved: function(model) {
console.log("_onModelRetrieved");
this.model = model;
this._readRecord(model);
},
_readRecord: function(model) {
var id = 13888228557;
console.log("_readRecord");
this.model.load(id, {
fetch: ['Name', 'Defects'],
callback: this._onRecordRead,
scope: this
});
},
_onRecordRead: function(record, operation) {
console.log('name...', record.get('Name'));
console.log('defects...', record.get('Defects'));
if(operation.wasSuccessful()) {
//load store first by passing additional config to getCollection method
var defectStore = record.getCollection('Defects', {
autoLoad: true,
listeners: { load: function() {
//once loaded now do the add and sync
defectStore.add({'_ref':'/defect/13303315495'});
defectStore.sync({
callback: function() {
console.log('success');
}
});
}}
});
}
},
});
Here is an example of creating a user story, setting a project and scheduling for an iteration:
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select an Iteration:',
labelWidth: 100,
width: 300
},
addContent: function() {
this._getIteration();
},
onScopeChange: function() {
this._getIteration();
},
_getIteration: function() {
var iteration = this.getContext().getTimeboxScope().record.get('_ref');
console.log('iteration',iteration);
if (!this.down('#b2')) {
var that = this;
var cb = Ext.create('Ext.Container', {
items: [
{
xtype : 'rallybutton',
text : 'create',
id: 'b2',
handler: function() {
that._getModel(iteration);
}
}
]
});
this.add(cb);
}
},
_getModel: function(iteration){
var that = this;
Rally.data.ModelFactory.getModel({
type: 'UserStory',
context: {
workspace: '/workspace/12352608129'
},
success: function(model) { //success on model retrieved
that._model = model;
var story = Ext.create(model, {
Name: 'story 777',
Description: 'created via appsdk2'
});
story.save({
callback: function(result, operation) {
if(operation.wasSuccessful()) {
console.log("_ref",result.get('_ref'), ' ', result.get('Name'));
that._record = result;
that._readAndUpdate(iteration);
}
else{
console.log("?");
}
}
});
}
});
},
_readAndUpdate:function(iteration){
var id = this._record.get('ObjectID');
console.log('OID', id);
this._model.load(id,{
fetch: ['Name', 'FormattedID', 'ScheduleState', 'Iteration'],
callback: function(record, operation){
console.log('ScheduleState prior to update:', record.get('ScheduleState'));
console.log('Iteration prior to update:', record.get('Iteration'));
record.set('ScheduleState','In-Progress');
record.set('Iteration', iteration);
record.set('Project', '/project/12352608219')
record.save({
callback: function(record, operation) {
if(operation.wasSuccessful()) {
console.log('ScheduleState after update..', record.get('ScheduleState'));
console.log('Iteration after update..', record.get('Iteration'));
}
else{
console.log("?");
}
}
});
}
})
}
});