I am getting error when I try to use bs-typeahead on an object. The error message gets displayed when I start typing in the text box
Below is the html:
<input type="text" class="form-control input-lg" id="city" name="city" ng-model="data.cityState" placeholder="City" ng-options="subscribedTown.id as subscribedTown.label for (index, subscribedTown) in data.subscribedTowns" bs-typeahead>
Below is the js:
var oostApp = angular.module('oostApp', ['mgcrea.ngStrap']);
oostApp.controller('SearchController', ['$scope', function ($scope) {
$scope.data = {};
$scope.data.cityState = '';
$scope.data.subscribedTowns = {
'54bd7820104d630153f62a06': {
id: "54bd7820104d630153f62a06", label: "Bloomfield, CT", name: "Bloomfield", state: "CT"
},
'54bd7829104d630153f66082': {
id: "54bd7829104d630153f66082", label: "Manchester, CT", name: "Manchester", state: "CT"
}
};
}]);
Below is the plunker:
http://embed.plnkr.co/XFMMUfTLmmvNXn2quO0Y
The error I get in Google chrome is
TypeError: undefined is not a function
at i (typeahead.js:259)
at typeahead.js:259
at l.promise.then.F (angular.js:11573)
at l.promise.then.F (angular.js:11573)
at angular.js:11659
at k.$get.k.$eval (angular.js:12702)
at k.$get.k.$digest (angular.js:12514)
at k.$get.k.$apply (angular.js:12806)
at angular.js:1447
at Object.d [as invoke] (angular.js:3966)
I don't know why you are using objects within an object and giving it the object id as a key while the object has the same id value in it. I think it is better to use an array and this might also create that error you are getting. The id value is included in every object, so there is no need to duplicate this as a key for the whole object. It's easier and faster to iterate over an array and the online examples on AngularStrap also use an array.
Source: https://mgcrea.github.io/angular-strap/#/typeaheads#typeaheads
This way you can go in the object directly and get all the values you need to work with the typeahead from AngularStrap.
Here is a possible solution:
http://plnkr.co/edit/5AewKg?p=preview
The undefined function I am getting now is from Plunker. I don't get this every time and it's never there when I test the code local. Let me know if it works for you. Typing B will trigger both possibilities.
Another small note:
angular.module('appName', []); // This is the angular module setter
angular.module('appName'); // This is the angular getter
Source: github.com/johnpapa/angularjs-styleguide#modules
Related
This is a follow on to "APEX row selector" posted 5 days ago.
The problem was collecting multiple values from an interactive grid. From the excellent links to post supplied I was able to achieve this. However, the next part of the project is to open an edit dialog page and update multiple values.
I added this code to the attribute of the interactive grid:
function (config)
{
var $ = apex.jQuery,
toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),
toolbarGroup = toolbarData.toolbarFind("actions3");
toolbarGroup.controls.push(
{
type: "BUTTON",
action: "updateCar",
label: "Edit Selected Cars",
hot: true,
});
config.toolbarData = toolbarData;
config.initActions = function (actions)
{
// Defining the action for activate button
actions.add(
{
name: "updateCar",
label: "Edit Selected Cars",
action: updateCar
});
}
function updateCar(event, focusElement)
{
var i, records, model, record,
view = apex.region("ig_car").widget().interactiveGrid("getCurrentView");
var vid = "";
model = view.model;
records = view.getSelectedRecords();
if (records.length > 0)
{
for (i = 0; i < records.length; i++)
{
record = records[i];
alert("Under Development " + record[1]);
vid = vid + record[1] + "||";
apex.item("P18_CAR").setValue(vid);
// need to open next page here and pass parameters
}
}
}
return config;
}
I need to know how to open a form and have the parameter values available to pass to an oracle update script.
Thank you for any help you can provide. I did find some posts but I really need a good example. I have tried everything to no avail.
There are various ways you could do this. Here's one way, perhaps someone else will offer a more efficient option.
The JavaScript options for navigation in APEX are documented here:
https://docs.oracle.com/en/database/oracle/application-express/19.1/aexjs/apex.navigation.html
Since you're trying to open a separate page, you probably want to use apex.navigation.dialog, which is what APEX automatically uses when opening modal pages from reports, buttons, etc.
However, as noted in the doc, the URL for the navigation must be generated server-side for security purposes. You need a dynamic URL (one not known when the page renders), so you'll need a workaround to generate it. Once you have the URL, navigating to it is easy. So how do you get the URL? Ajax.
Create an Ajax process to generate the URL
Under the processing tab of the report/grid page, right-click Ajax Callback and select Create Process.
Set Name to GET_FORM_URL.
Set PL/SQL code to the following
code:
declare
l_url varchar2(512);
begin
l_url := apex_page.get_url(
p_application => :APP_ID,
p_page => 3,
p_items => 'P3_ITEM_NAME',
p_values => apex_application.g_x01
);
apex_json.open_object();
apex_json.write('url', l_url);
apex_json.close_object();
end;
Note that I'm using apex_item.get_url to get the URL, this is an alternative to apex_util.prepare_url. I'm also using apex_json to emit JSON for the response to the client.
Also, the reference to apex_application.g_x01 is important, as this will contain the selected values from the calling page. You'll see how this was set in the next step.
Open the URL with JavaScript
Enter the following code in the Function and Global Variable Declaration attribute of the calling page:
function openFormPage(ids) {
apex.server.process(
'GET_FORM_URL',
{
x01: ids.join(':')
},
{
success: function (data) {
var funcBody = data.url.replace(/^"javascript:/, '').replace(/\"$/,'');
new Function(funcBody).call(window);
},
error: function (jqXHR, textStatus, errorThrown) {
console.error(errorThrown);
// handle error
}
}
);
}
In this case, I'm using apex.server.process to call the server-side PL/SQL process. Note that I'm passing the value of ids.join(':') to x01. That value will become accessible in the PL/SQL code as apex_application.g_x01. You can use additional items, or you can pass a colon-delimited string of values to just one item (as I'm doing).
The URL that's returned to the client will not be a standard URL, it will be a JavaScript snippet that includes the URL. You'll need to remove the leading and trailing parts and use what's left to generate a dynamic function in JavaScript.
This is generally frowned upon, but I believe it's safe enough in this context since I know I can trust that the response from the process call is not malicious JavaScript code.
Add a security check!!!
Because you're creating a dynamic way to generate URLs to open page 3 (or whatever page you're targeting), you need to ensure that the modal page is protected. On that page, create a Before Header process that validates the value of P3_ITEM_NAME. If the user isn't supposed to be able to access those values, then throw an exception.
My code:
signup.emblem:
= validating-form onsubmit=(action 'signUp')
= input-field value=username
span {{usernameError}}
validating-form.js:
submit(event) {
console.log(this.get('username') //undefined
this.sendAction('onsubmit')
}
signup.js:
actions: {
signUp() {
console.log(this.get('username')) // value from input
}
}
As you can see the basic idea is some value in input gets validated in validating-form component and then if everything is fine it'll call some controller action or set some properties.
The problem is that apparently this form component isn't bind to properties from controller, even though its child component (input-field) is. Can you tell me what am I doing wrong here?
If I have to bind it explicitely, is there some way to do that with multiple properties at once?
The problem is that the standard input element isn't two-way bound to your username variable. You can bind it quickly using the action and mut helpers.
(example in handlebars, but you should be able to convert to emblem easily enough)
<input value={{username}} onblur={{action (mut username) value='target.value'}}>
This is saying:
on the onblur event
mut(ate) the username
to match the current target.value - which is the value of the input box
You can see evidence of this working in this twiddle
The other option is Input Helpers
I've not used these, as they don't follow the current Ember thinking of Data Down Actions Up, but it should be as simple as:
{{input value=username}}
And this will two-way-bind directly username.
don't know if block helper is the right name but hope you get the point.
In Ember 1.8.0-beta.2 i can not do
<img src="{{url}}">
Chrome gives me:
Uncaught TypeError: Cannot read property 'parentNode' of null
Uncaught TypeError: Cannot set property 'profileNode' of undefined
And Firefox gives me:
TypeError: ref is null
var parent = ref.parentNode;
The error comes from vendor.js
hydrateMorphs: function () {
var childViews = this.childViews;
var el = this._element;
for (var i=0,l=childViews.length; i<l; i++) {
var childView = childViews[i];
var ref = el.querySelector('#morph-'+i);
var parent = ref.parentNode; // This line
childView._morph = this.dom.insertMorphBefore(parent, ref);
parent.removeChild(ref);
}
}
I know that i simply can do a handlebars helper to output the img tag with right src but i want to be able to use the {{url}} to set a divs background property aswell.
(the url property is just a simplified version. In my app i have a helper thats takes an array of images and maxWidth to to give me the best picture depending on the width. But {{url}} does not work either)
forgot that I just can use unbound:
<img src="{{unbound url}}">
You can't use that syntax in ember handlebars. The accepted one is bind-attr.
Usage examples: http://emberjs.com/guides/templates/binding-element-attributes/
More info: http://www.emberist.com/2012/04/06/bind-and-bindattr.html
So let's say I'm storing <div>{{name}}</div> and <div>{{age}}</div> in my database.
Then I want to take the first HTML string and render it in a template - {{> template1}} which just renders the first string with the {{name}} handlebar in it. Then I want to give that newly generated template/html data, so that it can fill in the handlebar with the actual name from the database, so that we would get <div>John</div>. I've tried doing
<template name="firstTemplate">
{{#with dataGetter}}
{{> template1}}
{{/with}}
</template>
Where template1 is defined as
<template name="template1">
{{{templateInfo}}}
</template>
And templateInfo is the helper that returns the aforementioned html string with the handlebar in it from the database.
dataGetter is just this (just an example, I'm working with differently named collections)
Template.firstTemplate.dataGetter = function() {
return Users.findOne({_id: Session.get("userID")});
}
I can't get the {{name}} to populate. I've tried it a couple of different ways, but it seems like Meteor doesn't understand that the handlebars in the string need to be evaluated with the data. I'm on 0.7.0 so no Blaze, I can't upgrade at the moment due to the other packages I'm using, they just don't have 0.8+ version support as of yet. Any ideas on how I can get this to work are much appreciated.
In 1.0 none of the methods described above work. I got this to work with the function below defined in the client code. The key was to pass the options { isTemplate: true} to the compile function.
var compileTemplate = function(name, html_text) {
try {
var compiled = SpacebarsCompiler.compile(html_text, { isTemplate:true });
var renderer = eval(compiled);
console.log('redered:',renderer);
//Template[name] = new Template(name,renderer);
UI.Template.__define__(name, renderer);
} catch (err){
console.log('Error compiling template:' + html_text);
console.log(err.message);
}
};
The you can call with something like this on the client:
compileTemplate('faceplate', '<span>Hello!!!!!!{{_id}}</span>');
This will render with a UI dynamic in your html
{{> Template.dynamic template='faceplate'}}
You can actually compile strings to templates yourself using the spacebars compiler.. You just have to use meteor add spacebars-compiler to add it to your project.
In projects using 0.8.x
var compiled = Spacebars.compile("<div>{{name}}</div> and <div>{{age}}</div>");
var rendered = eval(compiled);
Template["dynamicTemplate"] = UI.Component.extend({
kind: "dynamicTemplate",
render: rendered
});
In projects using 0.9.x
var compiled = SpacebarsCompiler.compile("<div>{{name}}</div> and <div>{{age}}</div>");
var renderer = eval(compiled);
Template["dynamicTemplate"] = Template.__create__("Template.dynamicTemplate", rendered);
Following #user3354036's answer :
var compileTemplate = function(name, html_text) {
try {
var compiled = SpacebarsCompiler.compile(html_text, { isTemplate:true }),
renderer = eval(compiled);
console.log('redered:',renderer);
//Template[name] = new Template(name,renderer);
UI.Template.__define__(name, renderer);
} catch (err) {
console.log('Error compiling template:' + html_text);
console.log(err.message);
}
};
1) Add this in your HTML
{{> Template.dynamic template=template}}
2) Call the compileTemplate method.
compileTemplate('faceplate', '<span>Hello!!!!!!{{_id}}</span>');
Session.set('templateName','faceplate');
Save the template name in a Session variable. The importance of this is explained in the next point.
3) Write a helper function to return the template name. I have used Session variable to do so. This is important if you are adding the dynamic content on a click event or if the parent template has already been rendered. Otherwise you will never see the dynamic template getting rendered.
'template' : function() {
return Session.get('templateName');
}
4) Write this is the rendered method of the parent template. This is to reset the Session variable.
Session.set('templateName','');
This worked for me. Hope it helps someone.
If you need to dynamically compile complex templates, I would suggest Kelly's answer.
Otherwise, you have two options:
Create every template variation, then dynamically choose the right template:
eg, create your templates
<template name="displayName">{{name}}</template>
<template name="displayAge">{{age}}</template>
And then include them dynamically with
{{> Template.dynamic template=templateName}}
Where templateName is a helper that returns "age" or "name"
If your templates are simple, just perform the substitution yourself. You can use Spacebars.SafeString to return HTML.
function simpleTemplate(template, values){
return template.replace(/{{\w+}}/g, function(sub) {
var p = sub.substr(2,sub.length-4);
if(values[p] != null) { return _.escape(values[p]); }
else { return ""; }
})
}
Template.template1.helpers({
templateInfo: function(){
// In this context this/self refers to the "user" data
var templateText = getTemplateString();
return Spacebars.SafeString(
simpleTemplate(templateText, this)
);
}
Luckily, the solution to this entire problem and any other problems like it has been provided to the Meteor API in the form of the Blaze package, which is the core Meteor package that makes reactive templates possible. If you take a look at the linked documentation, the Blaze package provides a long list of functions that allow for a wide range of solutions for programmatically creating, rendering, and removing both reactive and non-reactive content.
In order to solve the above described problem, you would need to do the following things:
First, anticipate the different HTML chunks that would need to be dynamically rendered for the application. In this case, these chunks would be <div>{{name}}</div> and <div>{{age}}</div>, but they could really be anything that is valid HTML (although it is not yet part of the public API, in the future developers will have more options for defining this content in a more dynamic way, as mentioned here in the documentation). You would put these into small template definitions like so:
<template name="nameDiv">
<div>{{name}}</div>
</template>
and
<template name="ageDiv">
<div>{{age}}</div>
</template>
Second, the definition for the firstTemplate template would need to be altered to contain an HTML node that can be referenced programmatically, like so:
<template name="firstTemplate">
<div></div>
</template>
You would then need to have logic defined for your firstTemplate template that takes advantage of some of the functions provided by the Blaze package, namely Blaze.With, Blaze.render, and Blaze.remove (although you could alter the following logic and take advantage of the Blaze.renderWithData function instead; it is all based on your personal preference for how you want to define your logic - I only provide one possible solution below for the sake of explanation).
Template.firstTemplate.onRendered(function() {
var dataContext = Template.currentData();
var unrenderedView = Blaze.With(dataContext, function() {
// Define some logic to determine if name/age template should be rendered
// Return either Template.nameDiv or Template.ageDiv
});
var currentTemplate = Template.instance();
var renderedView = Blaze.render(unrenderedView, currentTemplate.firstNode);
currentTemplate.renderedView = renderedView;
});
Template.firstTemplate.onDestroyed(function() {
var renderedView = Template.instance().renderedView;
Blaze.remove(renderedView);
});
So what we are doing here in the onRendered function for your firstTemplate template is dynamically determining which of the pieces of data that we want to render onto the page (either name or age in your case) and using the Blaze.With() function to create an unrendered view of that template using the data context of the firstTemplate template. Then, we select the firstTemplate template element node that we want the dynamically generated content to be contained in and pass both objects into the Meteor.render() function, which renders the unrendered view onto the page with the specified element node as the parent node of the rendered content.
If you read the details for the Blaze.render() function, you will see that this rendered content will remain reactive until the rendered view is removed using the Blaze.remove() function, or the specified parent node is removed from the DOM. In my example above, I am taking the reference to the rendered view that I received from the call to Blaze.render() and saving it directly on the template object. I do this so that when the template itself is destroyed, I can manually remove the rendered view in the onDestroyed() callback function and be assured that it is truly destroyed.
A very simple way is to include in the onRendered event a call to the global Blaze object.
Blaze.renderWithData(Template[template_name], data ,document.getElementById(template_id))
once a certain process is done I need to set a boolean to true in order to update the template.
I can easily get the object, but setting a property seems to be more difficult. What I use to get the object is
var found = self.get('content').findProperty('id', self.datasetid);
If I do that in the chrome console I can clearly see that I get an ember object back:
Object {id: 1, active: true}
__ember1364221685101_meta: Meta
active: true
get data_set: function () {
id: 1
set data_set: function (value) {
__proto__: Object
When I do:
found.set('data_set.fully_geocoded', true);
I do get the error mentioned in title. I've tried as many different flavours as I could think of, but all with the same result.
Could somebody shine a light on this?
An Object isn't an instance of Ember.Object, but the base Javascript class Object, so it won't have a get and set method.
You can get much of the same functionality by using Ember.get and Ember.set directly, passing in the object, as such:
Ember.set(found, 'data_set.fully_geocoded', true)
Ember.get(found, 'data_set.fully_geocoded')
Computed properties and observers can also fire based on using Ember.set this way.