Background: Our application is built on Angular. And I was trying to get access to underlying property of any of the component using Javascript.
For Eg:
HTML
<span class='course-list'>{{ totalCourses }}</span>
TypeScript
totalCourses = 5 //This is backend value
Using JavaScript is it possible to get access to the component instance totalCourses value..
So far I could reach till here
JS solution:
componentInstance = window.document.querySelector('course-list-detials')
// course-list-detials = this is selector for the component
by console logging this I was able to get html code for this 'course-list-detials'
We are trying to get access to component instances here. Since totalCourses value consists of backend value and we are trying to assert if the value matches with the rendered value in page using JS.
PLEASE help me!! I really need help. Any clue would also be really helpful
Thank you
Related
TypeError: cannot set properties of null (setting 'innerHtml')
I have created a simple angular service that initializes the inner html of a div tag in the main component of my angular project and is called in multiple components. When I run my tests I get the above karma error. I assume this is because the component is not created in the service.spec.ts file. I have checked and the class is defined in the main html file.
service.ts function:
onCLick(value: string): void {
document.querySelector('div.class').innerHtml = value;
}
service.spec.ts:
descirbe('ClickedService', () => {
let service: ClickedService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ClickedService);
});
to("#onClick should add to innerHtml", () => {
service.onClick('test value'); // error is here
});
});
welcome to the StackOverflow. To be honest, I wouldn't bother with fixing this unit test, because it looks like your approach to update the value is completely incorrect in the first place.
In Angular world, Service should provide you with values, and it can obtain them either from server via HTTP, or as a result of internal calculation. Then it's up to a Component, which is using this service, to deal with the value and display it if needed.
The reason why your test is not working is, that while creating the TestBed for the service, HTML is not expected and you are not providing any. Your querySelector within the service can't find the div you are looking for and you can't set innerHtml value to null.
If you really want to make this value and this logic available within the application, move it to a standalone component. You can then add it wherever you want, it will wrap the logic and it will prevent the repetition of the code. Don't use service with JS queries to update HTML, this will only lead to serious issues in the future.
Check this article about binding in angular to get better idea of what to do.
While working with React, i would like to display component name in an attribute of the component. E.g. if I have a component <LoginBox /> I would like it to be rendered as
<div data-react-name="LoginBox">...</div>
But I want this to be done automatically for each transpiled component. Reason for this is automated testing when I'd check for rendered elements in HTML/DOM, currently a component is not differentiated by the name in rendered HTML.
I thought I'd write a babel plugin, but I have no idea what visitors I'd use and how to make it robust enough. I tried google for such a plugin but I have no idea how it would be called and found nothing useful.
So is there any plugin or any way to achieve this?
Thanks
Now after a year, as I'm rethinking, it should be quite easy.
For more details on writing plugins see handbook.
Use ASTexplorer to inspect what AST would your code result in. And then, for generated tree, prepare visitors. So e.g. with code:
<div><Custom some-prop="prop">Some text</Custom></div>
we would infer, that we need to use visitor JSXOpeningElement and alter node's property attribute. To this property - array we would add a new element that we would create by Babel.types.jsxAttribute(name, value). We will get the name of tag from node's property .name.name (the name string is nested inside name object). We also need to use appropriate types. So it would look like this:
module.exports = function(Babel) {
return {
visitor: {
JSXOpeningElement(path) {
const name = Babel.types.jsxIdentifier('data-testname');
const value = Babel.types.stringLiteral(path.node.name.name);
path.node.attributes.push(Babel.types.jsxAttribute(name, value));
}
}
};
};
The code is tested with the ASTExplorer.
It seems like I'm having a pretty simple problem but can't seem to find a solution.
I’m trying to convert an application from vanilla JS to the angular framework. Previously, my program had an array of objects, and clicking a button would trigger a function which would just toggle one object’s boolean value between true or false. The objects with value “true” would then be filtered out and displayed further down the page.
The function was...
function addRepair(here, needed) {
possibleRepairs[here].isNeeded = needed;
var filteredArray = possibleRepairs.filter(ind => ind.isNeeded).map(ind => ind.area + " " + ind.repair).join("\<br\>");
document.getElementById('repairsGoHere').innerHTML = filteredArray;
}
I’m having trouble recreating this in angular. I think I’ve figured out most pieces of the process, but I don’t know how to code the function that’s supposed to do the actual toggle. Basically, I’m not sure how to access the array that I’ve created and change the boolean assignment.
So far in Angular I’ve created a class “repairs” and in my file app.component.ts I’ve exported a list of “repairs” in repairList like so…
repairList = [
new repairs("Front wheel", "out of true",false),
new repairs("Front hub", "needs tightening", false),
...
];
In the app.component.html I’ve created a button which is supposed to do the toggle…
<button type="button" onclick="addRepair('0', true);">Out of true</button>
which calls a function (which I know has been imported properly)...
function addRepair(here, needed) {
repairList[here].isNeeded = needed;
}
and later on the page will display data as so…
<div class="col-md-8" id="repairsGoHere" ng-repeat="inst in repairList | filter: {isNeeded:true}">
<p>{{ inst.area }}</p>
</div>
any advice on how to code the function to get it to do what I’d like? Or should I be approaching this a totally different way?
Thanks for all the help!
Evan
After getting some responses on here y'all helped me figure it out - I was coding in Angular 6 and didn't realize ng-repeat was from the AngularJS-era. Ang 6 doesn't have the same filter features so I'll need to figure out how to achieve the same result as I was seeking. Thanks for all the input!
how can I dynamically create a component in ember 1.13.13. I want to create it programmaticaly, inside another component.
This used to work in Ember 1.11.
var component = this.get('container').lookupFactory("component:my-component");
var view = this.createChildView(component, {param1: 'param1'});
view.createElement();
Ember.$('body').append(view.element);
view.didInsertElement(); // manually call didInsertElement
The same piece of code doesn't work in ember 1.13+, and although it doesn't throw any errors, the component's div element is empty. It is like the template is not rendered. Thanks you for your help.
Thanks for the suggestions I received in the comments. I decided to rethink my components and use the each helper to get around this. I would advise everybody else to do the same.
I have 1 main component. Inside of this component i use WebSockets to receive data from the server. I receive an object with a range of fields inside it. The number of fileds can be from 0 till 10, for example. Each time i receive an object i use forEach() to take all fields. For each field i need to init a component, like this:
self.dcl.loadIntoLocation(StreamComponent, self.elementRef, 'stream');
If a copy of a component for current field of an object already exists, i need to update it with new received data within the view. The main my problem is i don't know how to pass the data from WebSockets to created component. I can create and init it, but i never mind how to pass data to it. Any ideas ?
You could try to leverage the promise returned by the method:
self.dcl.loadIntoLocation(
StreamComponent, self.elementRef, 'stream').then((compRef:ComponentRef) => {
compRef.instance.someAttr = something;
});
This promise allows you to get the instance of the newly created component and set data in its properties (for example, the web socket).